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

nginx的nginScript实例分析

Nginx JavaScript server backend 670    来源:    2025-04-23

Nginx的nginScript实例分析

nginScript是Nginx的JavaScript实现,允许在Nginx配置中使用JavaScript来扩展功能。下面我将通过几个实例来分析nginScript的使用。

基本概念

nginScript是Nginx的一个模块,它: - 基于ECMAScript 5.1 (ES5)标准 - 专为Nginx配置和请求处理设计 - 在Nginx的不同处理阶段执行

实例1:简单的请求重写

js_include /etc/nginx/conf.d/rewrite.js;

server {
    listen 80;
    server_name example.com;

    location / {
        js_content rewriteExample;
    }
}

rewrite.js文件内容:

function rewriteExample(r) {
    r.log("Request URI: " + r.uri);

    if (r.uri === '/old-path') {
        r.uri = '/new-path';
        r.internalRedirect('/new-path');
    } else {
        r.return(200, "Hello from nginScript!");
    }
}

分析: - js_include指令加载JavaScript文件 - js_content指定处理请求的JavaScript函数 - r对象代表请求对象,提供了多种方法 - 可以根据URI进行重定向或返回自定义响应

实例2:请求验证

js_include /etc/nginx/conf.d/auth.js;

server {
    listen 80;
    server_name api.example.com;

    location /secure {
        js_content validateRequest;
    }
}

auth.js文件内容:

function validateRequest(r) {
    var authHeader = r.headersIn['Authorization'];

    if (!authHeader || authHeader !== 'Bearer valid-token') {
        r.return(401, "Unauthorized");
        return;
    }

    r.return(200, "Access granted");
}

分析: - 检查请求头中的Authorization字段 - 验证不通过返回401状态码 - 验证通过返回200状态码 - 适用于简单的API认证场景

实例3:动态代理

js_include /etc/nginx/conf.d/proxy.js;

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

server {
    listen 80;
    server_name dynamic.example.com;

    location / {
        js_content dynamicProxy;
    }
}

proxy.js文件内容:

function dynamicProxy(r) {
    var userAgent = r.headersIn['User-Agent'];
    var backend;

    if (userAgent.includes('Mobile')) {
        backend = 'http://mobile-backend.example.com';
    } else {
        backend = 'http://desktop-backend.example.com';
    }

    r.internalRedirect('@proxy_to_' + backend);
}

分析: - 根据User-Agent动态选择后端服务 - 使用internalRedirect进行内部重定向 - 可以实现基于设备类型的路由

实例4:响应处理

js_include /etc/nginx/conf.d/response.js;

server {
    listen 80;
    server_name transform.example.com;

    location / {
        proxy_pass http://backend;
        js_body_filter modifyResponse;
    }
}

response.js文件内容:

function modifyResponse(data, flags) {
    if (!flags.last) {
        return;
    }

    var newData = data.replace(/foo/g, 'bar');
    ngx.sendBuffer(newData);
}

分析: - js_body_filter用于修改响应体 - 可以替换、添加或删除响应内容 - 适用于内容转换或响应修改场景

实例5:复杂路由逻辑

js_include /etc/nginx/conf.d/router.js;

server {
    listen 80;
    server_name router.example.com;

    location / {
        js_content routeRequest;
    }
}

router.js文件内容:

function routeRequest(r) {
    var uri = r.uri;
    var args = r.args;
    var cookies = r.headersIn['Cookie'];

    // 基于路径的路由
    if (uri.startsWith('/api/v1')) {
        r.internalRedirect('@api_v1');
        return;
    }

    // 基于查询参数的路由
    if (args['version'] === '2') {
        r.internalRedirect('@api_v2');
        return;
    }

    // 基于cookie的路由
    if (cookies && cookies.includes('preferred_lang=en')) {
        r.internalRedirect('@english_content');
        return;
    }

    // 默认路由
    r.internalRedirect('@default_backend');
}

分析: - 实现复杂的路由逻辑 - 可以基于URI、查询参数、cookie等多种条件路由 - 比纯Nginx配置更灵活

性能考虑

  1. 执行阶段:nginScript可以在不同阶段执行,选择合适阶段很重要

    • js_content:内容生成阶段
    • js_body_filter:响应体过滤阶段
    • js_header_filter:响应头过滤阶段
  2. 避免阻塞操作:nginScript是同步执行的,长时间操作会影响性能

  3. 内存使用:复杂的JavaScript逻辑可能增加内存消耗

调试技巧

  1. 使用r.log()记录调试信息到Nginx错误日志
  2. 设置js_var在Nginx配置和JavaScript之间传递变量
  3. 使用try-catch捕获和处理异常

限制

  1. 不支持完整的Node.js API
  2. 基于ES5,不支持ES6+特性
  3. 性能不如原生Nginx模块

nginScript为Nginx提供了强大的脚本能力,特别适合需要复杂逻辑但又不想开发完整Nginx模块的场景。