JS#

该模块用于在 njs 中实现处理程序 —— JavaScript 语言的一个子集。

在我们的代码库中,该模块是 动态构建的 ,并作为一个独立的软件包提供,名为 angie-module-njsangie-pro-module-njs

配置示例#

http {
    js_import http.js;

    js_set $foo     http.foo;
    js_set $summary http.summary;
    js_set $hash    http.hash;

    resolver 127.0.0.53;

    server {
        listen 8000;

        location / {
            add_header X-Foo $foo;
            js_content http.baz;
        }

        location = /summary {
            return 200 $summary;
        }

        location = /hello {
            js_content http.hello;
        }

        location = /fetch {
            js_content                   http.fetch;
            js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
        }

        location = /crypto {
            add_header Hash $hash;
            return     200;
        }
    }
}

http.js 文件:

function foo(r) {
    r.log("hello from foo() handler");
    return "foo";
}

function summary(r) {
    var a, s, h;

    s = "JS summary\n\n";

    s += "Method: " + r.method + "\n";
    s += "HTTP version: " + r.httpVersion + "\n";
    s += "Host: " + r.headersIn.host + "\n";
    s += "Remote Address: " + r.remoteAddress + "\n";
    s += "URI: " + r.uri + "\n";

    s += "Headers:\n";
    for (h in r.headersIn) {
        s += "  header '" + h + "' is '" + r.headersIn[h] + "'\n";
    }

    s += "Args:\n";
    for (a in r.args) {
        s += "  arg '" + a + "' is '" + r.args[a] + "'\n";
    }

    return s;
}

function baz(r) {
    r.status = 200;
    r.headersOut.foo = 1234;
    r.headersOut['Content-Type'] = "text/plain; charset=utf-8";
    r.headersOut['Content-Length'] = 15;
    r.sendHeader();
    r.send("nginx");
    r.send("java");
    r.send("script");

    r.finish();
}

function hello(r) {
    r.return(200, "Hello world!");
}

async function fetch(r) {
    let results = await Promise.all([ngx.fetch('https://google.com/'),
                                     ngx.fetch('https://google.ru/')]);

    r.return(200, JSON.stringify(results, undefined, 4));
}

async function hash(r) {
    let hash = await crypto.subtle.digest('SHA-512', r.headersIn.host);
    r.setReturnValue(Buffer.from(hash).toString('hex'));
}

export default {foo, summary, baz, hello, fetch, hash};

指令#

js_body_filter#

语法

js_body_filter function | module.function [buffer_type=string | buffer];

默认值

上下文

location, if in location, limit_except

设置一个 njs 函数作为响应体过滤器。过滤器函数为响应体的每个数据块调用,并具有以下参数:

r

HTTP 请求 对象

data

传入的数据块,可能是字符串或缓冲区,取决于 buffer_type 的值,默认是字符串。

flags

一个包含以下属性的对象:
last — 一个布尔值

true — 如果数据是最后一个缓冲区。

过滤器函数可以通过调用 r.sendBuffer() 将其修改后的输入数据块传递给下一个体过滤器。例如,要将响应体中的所有小写字母转换:

function filter(r, data, flags) {
    r.sendBuffer(data.toLowerCase(), flags);
}

要停止过滤(后续数据块将直接传递给客户端而不调用 js_body_filter),可以使用 r.done()

如果过滤器函数更改了响应体的长度,则需要在 js_header_filter 中清除 "Content-Length" 响应头(如果有)以强制分块传输编码。

备注

由于 js_body_filter 处理程序立即返回其结果,仅支持同步操作。因此,不支持异步操作,如 r.subrequest()setTimeout()

js_content#

语法

js_content function | module.function;

默认值

上下文

location, if in location, limit_except

设置一个 njs 函数作为位置内容处理程序。可以引用模块函数。

js_fetch_buffer_size#

语法

js_fetch_buffer_size size;

默认值

js_fetch_buffer_size 16k;

上下文

http, server, location

设置用于通过 Fetch API 读取和写入的缓冲区大小。

js_fetch_ciphers#

语法

js_fetch_ciphers ciphers;

默认值

js_fetch_ciphers HIGH:!aNULL:!MD5;

上下文

http, server, location

指定用于通过 Fetch API 的 HTTPS 连接的启用密码。密码以 OpenSSL 库能够理解的格式指定。

可以使用 "openssl ciphers" 命令查看完整列表。

js_fetch_max_response_buffer_size#

语法

js_fetch_max_response_buffer_size size;

默认值

js_fetch_max_response_buffer_size 1m;

上下文

http, server, location

设置通过 Fetch API 接收的响应的最大大小。

js_fetch_protocols#

语法

js_fetch_protocols [TLSv1] [TLSv1.1] [TLSv1.2] [TLSv1.3];

默认值

js_fetch_protocols TLSv1 TLSv1.1 TLSv1.2;

上下文

http, server, location

启用通过 Fetch API 的 HTTPS 连接的指定协议。

js_fetch_timeout#

语法

js_fetch_timeout time;

默认值

js_fetch_timeout 60s;

上下文

http, server, location

定义 Fetch API 读取和写入的超时时间。超时时间仅在两次连续的读/写操作之间设置,而不是针对整个响应。如果在此时间内没有数据传输,连接将关闭。

js_fetch_trusted_certificate#

语法

js_fetch_trusted_certificate file;

默认值

上下文

http, server, location

指定一个包含 CA 证书的 PEM 格式文件,用于通过 Fetch API 验证 HTTPS 证书。

js_fetch_verify#

语法

js_fetch_verify on | off;

默认值

js_fetch_verify on;

上下文

http, server, location

启用或禁用通过 Fetch API 验证 HTTPS 服务器证书。

js_fetch_verify_depth#

语法

js_fetch_verify_depth number;

默认值

js_fetch_verify_depth 100;

上下文

http, server, location

设置通过 Fetch API 的 HTTPS 服务器证书链验证深度。

js_header_filter#

语法

js_header_filter function | module.function;

默认值

上下文

location, if in location, limit_except

设置一个 njs 函数作为响应头过滤器。该指令允许更改响应头的任意字段。

备注

由于 js_header_filter 处理程序立即返回其结果,仅支持同步操作。因此,不支持异步操作,如 r.subrequest()setTimeout()

js_import#

语法

js_import module.js | export_name from module.js;

默认值

上下文

http, server, location

导入一个在 njs 中实现位置和变量处理程序的模块。export_name 用作命名空间来访问模块函数。如果未指定 export_name,则使用模块名称作为命名空间。

js_import http.js;

在这里,模块名称 http 用作访问导出的命名空间。如果导入的模块导出 foo(),则使用 http.foo 来引用它。

可以指定多个 js_import 指令。

js_path#

语法

js_path path;

默认值

上下文

http, server, location

设置 njs 模块的附加路径。

js_preload_object#

语法

js_preload_object name.json | name from file.json;

默认值

上下文

http, server, location

在配置时预加载一个不可变对象。name 用作全局变量的名称,通过该变量可以在 njs 代码中访问对象。如果未指定 name,则使用文件名作为变量名。

js_preload_object map.json;

在此示例中,map 被用作访问预加载对象时的名称。

可以指定多个 js_preload_object 指令。

js_set#

语法

js_set $variable function | module.function;

默认值

上下文

http, server, location

为指定变量设置 njs 函数。可以引用模块函数。

该函数在请求中首次引用变量时调用。具体时间取决于引用变量的 阶段。这可以用于执行一些与变量评估无关的逻辑。例如,如果变量仅在 log_format 指令中引用,则其处理程序将在日志阶段才执行。此处理程序可用于在请求释放前进行一些清理工作。

备注

由于 js_set 处理程序立即返回其结果,因此仅支持同步回调。因此,不支持诸如 r.subrequest()setTimeout() 的异步回调。

js_shared_dict_zone#

语法

js_shared_dict_zone zone=name:size [timeout=time] [type=string | number] [evict];

默认值

上下文

http

设置共享内存区域的名称和大小,该区域在工作进程之间共享键值字典。

type

可选参数,允许将值类型重新定义为 number
默认情况下,共享字典使用 string 作为键和值。

timeout

可选参数,设置共享字典条目从区域中移除的时间。

evict

可选参数,当区域存储耗尽时,移除最旧的键值对。

示例:

example.conf:
    # 创建一个具有字符串值的 1Mb 字典,
    # 在 60 秒不活动后移除键值对:
    js_shared_dict_zone zone=foo:1M timeout=60s;

    # 创建一个具有字符串值的 512Kb 字典,
    # 当区域耗尽时强制移除最旧的键值对:
    js_shared_dict_zone zone=bar:512K timeout=30s evict;

    # 创建一个具有数字值的 32Kb 永久字典:
    js_shared_dict_zone zone=num:32k type=number;

example.js:
    function get(r) {
        r.return(200, ngx.shared.foo.get(r.args.key));
    }

    function set(r) {
        r.return(200, ngx.shared.foo.set(r.args.key, r.args.value));
    }

    function delete(r) {
        r.return(200, ngx.shared.bar.delete(r.args.key));
    }

    function increment(r) {
        r.return(200, ngx.shared.num.incr(r.args.key, 2));
    }

js_var#

语法

js_var $variable [value];

默认值

上下文

stream, server

声明一个 可写 变量。值可以包含文本、变量及其组合。与通过 set 指令创建的变量不同,该变量在重定向后不会被覆盖。

请求参数#

每个 HTTP njs 处理程序接收一个参数,即 request 对象。