插件窝 干货文章 nginx的JavaScript能力nginScript实例分析

nginx的JavaScript能力nginScript实例分析

JavaScript Nginx internalRedirect headersIn 547    来源:    2025-04-26

Nginx JavaScript (njs) 实例分析

njs 是 Nginx 的 JavaScript 子集实现,允许在 Nginx 配置中使用 JavaScript 进行复杂的请求处理。以下是对 njs 能力的详细分析和实例展示。

1. njs 基本能力

njs 提供了以下核心功能: - 变量操作和类型处理 - 正则表达式 - 字符串和数组操作 - HTTP 请求/响应处理 - 异步操作支持

2. 安装与配置

安装 njs 模块

# Debian/Ubuntu
apt install nginx-module-njs

# CentOS/RHEL
yum install nginx-module-njs

Nginx 配置加载

load_module modules/ngx_http_js_module.so;
load_module modules/ngx_stream_js_module.so;

3. 实用实例分析

实例1:请求头修改

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 };

实例2:请求验证与过滤

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 };

实例3:动态路由

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 };

实例4:A/B 测试

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 };

实例5:请求日志增强

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 };

4. 性能考虑

  1. 避免复杂计算:njs 在请求处理路径中执行,应保持轻量
  2. 使用内置变量:优先使用 Nginx 内置变量而非 JavaScript 计算
  3. 缓存结果:对重复计算使用变量缓存
  4. 限制脚本大小:保持脚本简洁,复杂逻辑考虑使用其他服务

5. 调试技巧

  1. 使用 r.log() 记录调试信息
  2. 检查 Nginx 错误日志
  3. 使用 js_content 直接返回调试信息
  4. 逐步构建复杂脚本

6. 限制与注意事项

  1. 不是完整的 ECMAScript 实现
  2. 不支持 DOM 操作(浏览器API)
  3. 部分 JavaScript 特性不可用
  4. 性能敏感场景需谨慎使用

njs 为 Nginx 提供了强大的脚本能力,适合处理需要灵活逻辑但又不值得引入完整后端服务的场景。