njs 是 Nginx 的 JavaScript 子集实现,允许在 Nginx 配置中使用 JavaScript 进行复杂的请求处理。以下是对 njs 能力的详细分析和实例展示。
njs 提供了以下核心功能: - 变量操作和类型处理 - 正则表达式 - 字符串和数组操作 - HTTP 请求/响应处理 - 异步操作支持
# Debian/Ubuntu
apt install nginx-module-njs
# CentOS/RHEL
yum install nginx-module-njs
load_module modules/ngx_http_js_module.so;
load_module modules/ngx_stream_js_module.so;
http {
js_import /etc/nginx/njs/header_modifier.js;
server {
location / {
js_content header_modifier.process;
}
}
}
header_modifier.js
:
function process(r) {
// 添加自定义请求头
r.headersOut['X-Request-ID'] = Math.random().toString(36).substr(2, 9);
// 修改User-Agent
r.headersIn['User-Agent'] = 'njs-processed/' + r.headersIn['User-Agent'];
r.return(200, "Headers modified");
}
export default { process };
function auth(r) {
const token = r.headersIn['Authorization'];
if (!token || !token.startsWith('Bearer ')) {
r.return(401, "Unauthorized");
return;
}
const jwt = token.substr(7);
// 简单验证逻辑
if (jwt.length < 30) {
r.return(403, "Invalid token");
return;
}
r.internalRedirect('@backend');
}
export default { auth };
function route(r) {
const path = r.uri;
const device = r.headersIn['User-Agent'].includes('Mobile') ? 'mobile' : 'desktop';
if (path.startsWith('/api/')) {
r.internalRedirect('@api_backend');
} else if (device === 'mobile' && path === '/') {
r.return(302, '/mobile/index.html');
} else {
r.internalRedirect('@web_backend');
}
}
export default { route };
function abTest(r) {
const cookie = r.headersIn['Cookie'] || '';
const variant = cookie.includes('ab=v1') ? 'v1' :
cookie.includes('ab=v2') ? 'v2' :
Math.random() > 0.5 ? 'v1' : 'v2';
// 设置cookie
r.headersOut['Set-Cookie'] = `ab=${variant}; Path=/; Max-Age=86400`;
if (variant === 'v1') {
r.internalRedirect('@backend_v1');
} else {
r.internalRedirect('@backend_v2');
}
}
export default { abTest };
function logRequest(r) {
const logData = {
time: new Date().toISOString(),
ip: r.remoteAddress,
method: r.method,
uri: r.uri,
status: r.status,
referer: r.headersIn['Referer'] || '',
ua: r.headersIn['User-Agent'] || '',
responseTime: r.variables.request_time
};
// 写入自定义日志
r.log(JSON.stringify(logData));
r.internalRedirect('@backend');
}
export default { logRequest };
r.log()
记录调试信息js_content
直接返回调试信息njs 为 Nginx 提供了强大的脚本能力,适合处理需要灵活逻辑但又不值得引入完整后端服务的场景。