NGINX Unit

脚本编写§

NGINX Unit 的 控制 API 支持 JavaScript 表达式,包括函数调用,形式为 模板文字,用 NGINX JavaScript ( njs ) 编写。它们可与这些 配置 选项一起使用

  • pass侦听器操作 中,用于在路由、应用程序、应用目标或上游之间进行选择。

  • response_headers 值在 操作 中,用于处理响应头字段。

  • rewrite操作 中,用于启用 URI 重写

  • sharechroot操作 中,用于控制 静态内容服务

  • locationreturn 操作 中,用于启用 HTTP 重定向。

  • format访问日志 中,用于自定义 Unit 的日志输出。

  • if访问日志 中,用于动态地打开和关闭 Unit 的日志记录。

作为其 JavaScript 引擎,Unit 使用 njs 库,该库与 官方软件包 一起提供,或 从源代码构建

警告

Unit 1.32.0 及更高版本需要 njs 0.8.2

一些请求属性以 njs 对象或标量形式公开

名称

类型

说明

参数

对象

查询字符串参数;颜色=蓝色args.Color;可与Object.keys()一起使用。

cookies

对象

请求 cookie;authID cookie 是cookies.authID;可与Object.keys()一起使用。

headers

对象

请求标头字段;Acceptheaders.AcceptContent-Encodingheaders[‘Content-Encoding’](连字符需要一个数组属性访问器);可与Object.keys()一起使用。

host

标量

Host 标头字段,转换为小写并通过删除端口号和尾随句点(如果有)进行规范化。

remoteAddr

标量

请求的远程 IP 地址。

uri

标量

请求目标百分比解码并通过删除查询字符串和解析相对引用(“.”和“..”、“//”)进行规范化。

vars

对象

Unit 变量;vars.method 是$method

模板文字用反引号括起来。要在字符串中使用文字反引号,请转义它:\\`(转义反斜杠是JSON 要求)。njs 片段应括在大括号中:${…}

接下来,您可以上传并使用自定义 JavaScript 模块和您的配置。考虑这个http.js脚本,它通过Authorization标头字段值区分请求

var http = {}

http.route = function(headers) {
    var authorization = headers['Authorization'];
    if (authorization) {
        var user = atob(authorization.split(' ')[1]);
        if (String(user) == 'user:password') {
            return 'accept';
        }

        return 'forbidden';
    }

    return 'unauthorized';
}

export default http

要将其上传到 Unit 的 JavaScript 模块存储中,作为http

# curl -X PUT --data-binary @http.js --unix-socket /path/to/control.unit.sock \
      https://127.0.0.1/js_modules/http

Unit 默认情况下不会启用上传的模块,因此将模块的名称添加到settings/js_module

# curl -X PUT -d '"http"' /path/to/control.unit.sock \
      https://127.0.0.1/config/settings/js_module

注意

请注意,js_module选项可以是字符串或数组;选择适当的 HTTP 方法。

现在,http.route()函数可与 Unit 提供的标头字段值一起使用

{
    "routes": {
        "entry": [
            {
                "action": {
                    "pass": "`routes/${http.route(headers)}`"
                }
            }
        ],

        "unauthorized": [
            {
                "action": {
                    "return": 401
                }
            }
        ],

        "forbidden": [
            {
                "action": {
                    "return": 403
                }
            }
        ],

        "accept": [
            {
                "action": {
                    "return": 204
                }
            }
        ]
    }
}

示例§

此示例添加了简单的路由逻辑,该逻辑从User-Agent标头字段中提取代理名称,以拒绝由curl发出的请求

"routes": {
    "parse": [
        {
            "action": {
                "pass": "`routes/${ headers['User-Agent'].split('/')[0] == 'curl' ? 'reject' : 'default' }`"
            }
        }
    ],

    "reject": [
        {
            "action": {
                "return": 400
            }
        }
    ],

    "default": [
        {
            "action": {
                "return": 204
            }
        }
    ]
}

此示例使用一系列转换来记录请求的日期、IP、URI 及其所有标头

{
    "path": "/var/log/unit/access_kv.log",
    "format": "`@timestamp=${new Date().toISOString()} ip=${remoteAddr} uri=${uri} ${Object.keys(headers).map(k => 'req.' + k + '=\"' + headers[k] + '\"').join(' ')}\n`"
}

下一个示例将根据 HTTP 请求方法添加Cache-Control标头

{
    "action": {
      "pass": "applications/my_app",
      "response_headers": {
         "Cache-Control": "`${vars.method.startsWith('P') ? 'no-cache' : 'max-age=3600'}`"
      }
    }
}

如需进一步参考,请参阅njs 文档