JS#
该模块用于在 njs 中实现处理程序——这是 JavaScript 语言的一个子集。
在我们的代码库中,该模块是
动态构建
并作为名为 angie-module-njs 或 angie-pro-module-njs 的单独包提供。
备注
此软件包还提供一个轻量级版本,名为 ...-njs-light;但它无法与常规版本
同时使用。
配置示例#
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#
| |
默认 | — |
location, if in location, limit_except |
将 njs 函数设置为响应体过滤器。过滤函数在响应体的每个数据块上被调用,具有以下参数:
| HTTP 请求 对象 |
| 输入的数据块,可以是字符串或 Buffer,具体取决于 buffer_type 值,默认是字符串。 |
| 具有以下属性的对象:
- |
过滤函数可以通过调用 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#
将 njs 函数设置为位置内容处理程序。可以引用模块函数。
js_context_reuse#
设置 QuickJS 引擎可重用的 JS 上下文的最大数量。每个上下文用于单个请求。完成的上下文被放入可重用上下文池中。如果池已满,则销毁上下文。
js_engine#
设置用于 njs 脚本的 JavaScript 引擎。njs 参数设置 njs 引擎,也是默认使用的。qjs 参数设置 QuickJS 引擎。
js_fetch_buffer_size#
设置用于 Fetch API 读取和写入的缓冲区大小。
js_fetch_ciphers#
指定与 Fetch API 的 HTTPS 连接启用的密码。密码的格式与 OpenSSL 库理解的格式相同。
密码列表取决于已安装的 OpenSSL 版本。可以使用 openssl ciphers 命令查看完整列表。
js_fetch_max_response_buffer_size#
| |
默认 |
|
http, server, location |
设置通过 Fetch API 接收到的响应的最大大小。
js_fetch_protocols#
| |
默认 |
|
http, server, location |
启用与 Fetch API 的 HTTPS 连接的指定协议。
js_fetch_timeout#
定义 Fetch API 的读取和写入超时。超时仅在两个连续的读/写操作之间设置,而不是针对整个响应。如果在此时间内没有传输数据,连接将被关闭。
js_fetch_trusted_certificate#
指定一个包含 PEM 格式的受信任 CA 证书的文件,用于通过 Fetch API 验证 HTTPS 证书。
js_fetch_verify#
启用或禁用使用 Fetch API 验证 HTTPS 服务器证书。
js_fetch_verify_depth#
设置与 Fetch API 的 HTTPS 证书链中的验证深度。
js_fetch_keepalive#
激活到目标服务器的连接缓存。当值大于 0 时,为 Fetch API 启用 keepalive 连接。
connections 参数设置每个工作进程的缓存中保留的到目标服务器的空闲 keepalive 连接的最大数量。当超过此数量时,将关闭最近最少使用的连接。
示例:
location /fetch {
js_fetch_keepalive 32;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
js_content main.fetch_handler;
}
js_fetch_keepalive_requests#
设置通过 Fetch API 的一个 keepalive 连接可以处理的最大请求数。在达到最大请求数后,连接将被关闭。
定期关闭连接对于释放每个连接的内存分配是必要的。因此,使用过高的最大请求数可能会导致内存使用过多,不建议这样做。
js_fetch_keepalive_time#
限制通过 Fetch API 的一个 keepalive 连接可以处理请求的最长时间。达到此时间后,连接将在后续请求处理后关闭。
js_fetch_keepalive_timeout#
设置与 Fetch API 的到目标服务器的空闲 keepalive 连接保持打开的超时时间。
js_header_filter#
将 njs 函数设置为响应头过滤器。该指令允许更改响应头的任意字段。
备注
由于 js_header_filter 处理程序立即返回其结果,因此仅支持同步操作。因此,不支持异步操作,例如 r.subrequest() 或 setTimeout()。
js_import#
导入实现 njs 中位置和变量处理程序的模块。export_name 用作访问模块函数的命名空间。如果未指定 export_name,则将使用模块名称作为命名空间。
js_import http.js;
在这里,模块名称 http 被用作访问
导出的命名空间。如果导入的模块导出 foo(),则使用
http.foo 来引用它。
可以指定多个 js_import 指令。
js_path#
为 njs 模块设置额外的路径。
js_periodic#
| |
默认 | — |
location |
指定定期运行的内容处理程序。该处理程序接收会话对象作为其第一个参数,它还可以访问全局对象,如 ngx。
可选的 interval 参数设置两次连续运行之间的间隔,默认为 5 秒。
可选的 jitter 参数设置位置内容处理程序将被随机延迟的时间,默认情况下没有延迟。
默认情况下,:samp:js_handler 在工作进程 0 上执行。可选的 worker_affinity 参数允许指定应在其中执行位置内容处理程序的特定工作进程。每个工作进程集由允许的工作进程的位掩码表示。all 掩码允许处理程序在所有工作进程中执行。
示例:
example.conf:
location @periodics {
# 在工作进程 0 中以 1 分钟间隔运行
js_periodic main.handler interval=60s;
# 在所有工作进程中以 1 分钟间隔运行
js_periodic main.handler interval=60s worker_affinity=all;
# 在工作进程 1 和 3 中以 1 分钟间隔运行
js_periodic main.handler interval=60s worker_affinity=0101;
resolver 10.0.0.1;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}
example.js:
async function handler(s) {
let reply = await ngx.fetch('https://example.com/');
let body = await reply.text();
ngx.log(ngx.INFO, body);
}
js_preload_object#
在配置时预加载一个不可变对象。name 用作全局变量的名称,通过该变量可以在 njs 代码中访问对象。如果未指定 name,则将使用文件名。
js_preload_object map.json;
在这里,`map` 被用作访问预加载对象时的名称。
可以指定多个 js_preload_object 指令。
js_set#
为指定变量设置一个 njs 函数。可以引用模块函数。
当变量在给定请求中首次被引用时,该函数会被调用。确切的时刻取决于引用变量的 阶段。这可以用于执行一些与变量求值无关的逻辑。例如,如果变量仅在 log_format 指令中被引用,其处理程序将不会执行,直到日志阶段。此处理程序可用于在请求被释放之前进行一些清理工作。
从 njs 0.8.6 开始,如果指定了可选参数 nocache,则处理程序在每次被引用时都会被调用。由于 rewrite 模块当前的限制,当 nocache 变量被 set 指令引用时,其处理程序应始终返回固定长度的值。
备注
由于 js_set 处理程序立即返回其结果,因此仅支持同步操作。因此,不支持异步操作,如 r.subrequest() 或 setTimeout()。
js_var#
声明一个 可写 变量。 值可以包含文本、变量及其组合。 该变量在重定向后不会被覆盖,不像通过 set 指令创建的变量。
请求参数#
每个 HTTP njs 处理程序接收一个参数,即 请求 对象。