一、njs 核心基础:模块与配置入门
1. 模块加载与核心定位
ngx_http_js_module 是 njs 的核心模块,需先在 nginx 配置中加载(编译 nginx 时需启用该模块,或通过动态模块加载)。njs 主要用于实现两类核心能力:
- location 处理器:接管特定路径的请求处理(如返回自定义响应、调用外部接口);
- 变量处理器:自定义 nginx 变量,动态生成变量值。
2. 最简示例:快速上手
以下是 njs 基础配置与脚本示例,覆盖核心用法(适配 njs 0.4.0+ 版本):
步骤 1:nginx 主配置(nginx.conf)
http {
# 1. 导入 njs 脚本文件(核心指令:js_import)
js_import http.js;
# 2. 自定义 nginx 变量(js_set 绑定 njs 函数)
js_set $foo http.foo;
js_set $summary http.summary;
server {
listen 8000;
charset utf-8;
# 3. 自定义 content 处理器(js_content 绑定 njs 函数)
location / {
add_header x-foo $foo; # 使用自定义变量
js_content http.baz; # 接管响应内容
}
# 直接返回自定义变量值
location = /summary {
return 200 $summary;
}
# 简单的文本响应
location = /hello {
js_content http.hello;
}
}
}
步骤 2:njs 脚本文件(http.js)
// 1. 自定义变量处理器:返回固定值
function foo(r) {
r.log("执行 foo 变量处理器"); // 写入 nginx 日志
return "foo-value";
}
// 2. 自定义变量处理器:生成请求摘要信息
function summary(r) {
let s = "请求摘要信息\n\n";
// 读取请求对象(r)的核心属性
s += "请求方法:" + r.method + "\n";
s += "http 版本:" + r.httpversion + "\n";
s += "请求主机:" + r.headersin.host + "\n";
s += "客户端ip:" + r.remoteaddress + "\n";
s += "请求uri:" + r.uri + "\n";
// 遍历请求头
s += "请求头:\n";
for (let h in r.headersin) {
s += ` ${h}: ${r.headersin[h]}\n`;
}
// 遍历查询参数(r.args 自动解析 url 查询字符串)
s += "查询参数:\n";
for (let a in r.args) {
s += ` ${a}: ${r.args[a]}\n`;
}
return s;
}
// 3. 自定义 content 处理器:分步构建响应
function baz(r) {
r.status = 200; // 设置响应状态码
// 设置响应头
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();
}
// 4. 简化的响应方式:直接返回状态码+内容
function hello(r) {
r.return(200, "hello njs!");
}
// 导出函数(供 nginx 配置调用)
export default { foo, summary, baz, hello };
测试验证
- 访问 http://localhost:8000/hello:返回 hello njs!;
- 访问 http://localhost:8000/summary?name=test&age=20:返回包含请求方法、头信息、查询参数的摘要文本;
- 访问 http://localhost:8000/:返回 nginxjavascript(分段发送的内容拼接),响应头包含 x-foo: foo-value。
二、njs 核心指令详解
njs 的能力通过一系列专属指令实现,以下是高频使用的核心指令分类说明:
1. 脚本导入与基础指令
| 指令 | 作用 | 适用版本 |
|---|---|---|
| js_import | 导入 njs 模块(支持命名空间),替代旧版 js_include | 0.4.0+ |
| js_content | 将 njs 函数设为 location 内容处理器,接管请求响应 | 全版本 |
| js_set | 将 njs 函数绑定到 nginx 变量,函数返回值作为变量值 | 全版本 |
| js_path | 设置 njs 模块的额外加载路径 | 0.3.0+ |
| js_var | 声明可写的 nginx 变量(重定向后不重置) | 0.5.3+ |
关键说明:
- js_import 支持两种写法:
js_import http.js; # 以文件名作为命名空间(http.函数名) js_import myhttp from http.js; # 自定义命名空间(myhttp.函数名)
- js_include 已被废弃(0.7.1 移除),优先使用 js_import。
2. 响应过滤指令(修改响应内容/头)
| 指令 | 作用 | 适用版本 |
|---|---|---|
| js_header_filter | 设置响应头过滤器,修改/删除响应头(如清除 content-length) | 0.5.1+ |
| js_body_filter | 设置响应体过滤器,逐块修改响应内容(如大小写转换、内容替换) | 0.5.2+ |
实战示例:响应体小写转换
# nginx 配置
location /filter {
proxy_pass http://localhost:8080;
# 清除 content-length(避免长度不匹配)
js_header_filter http.clearcontentlength;
# 响应体过滤器:转小写
js_body_filter http.lowercasefilter;
}
// http.js 新增函数
function clearcontentlength(r) {
delete r.headersout['content-length'];
}
function lowercasefilter(r, data, flags) {
// 逐块处理响应体,转小写后传递给下一个过滤器
r.sendbuffer(data.tolowercase(), flags);
}
3. fetch api 相关指令(0.7.0+)
njs 0.7.0 新增 ngx.fetch 方法,支持发起 http/https 请求,配套指令用于配置请求规则:
| 指令 | 作用 |
|---|---|
| js_fetch_trusted_certificate | 指定 https 证书验证的可信 ca 文件(pem 格式) |
| js_fetch_verify | 启用/禁用 https 证书验证(生产环境建议开启) |
| js_fetch_timeout | 设置 fetch 请求的读写超时时间(默认 60s) |
| js_fetch_proxy | 配置 fetch 请求的正向代理(支持 http 代理,0.9.4+) |
| js_fetch_keepalive | 启用 fetch 连接池,设置最大空闲连接数(0.9.2+) |
实战示例:异步调用外部接口
# nginx 配置
location = /fetch {
js_content http.fetch;
js_fetch_trusted_certificate /path/to/isrg_root_x1.pem;
js_fetch_keepalive 32; # 连接池最大空闲连接数
}
// http.js 新增异步函数
async function fetch(r) {
try {
// 并行调用两个接口
let results = await promise.all([
ngx.fetch('https://nginx.org/'),
ngx.fetch('https://nginx.org/en/')
]);
// 解析响应并返回
let response = [];
for (let res of results) {
response.push({
status: res.status,
body: await res.text()
});
}
r.return(200, json.stringify(response, null, 2), {
'content-type': 'application/json; charset=utf-8'
});
} catch (e) {
r.return(500, `请求失败:${e.message}`);
}
}
4. 高级特性指令
4.1 共享字典(0.8.0+):跨 worker 进程共享数据
# nginx 配置:创建 1mb 共享字典,60s 超时,支持淘汰旧数据 js_shared_dict_zone zone=mydict:1m timeout=60s evict;
// http.js 操作共享字典
function setdict(r) {
// 设置键值对
let result = ngx.shared.mydict.set(r.args.key, r.args.value);
r.return(200, `设置结果:${result}`);
}
function getdict(r) {
// 获取键值对
let value = ngx.shared.mydict.get(r.args.key);
r.return(200, `获取结果:${value || '不存在'}`);
}
4.2 定时任务(0.8.1+):周期性执行函数
# nginx 配置:每分钟在所有 worker 进程执行定时任务
location @periodic {
js_periodic http.periodictask interval=60s worker_affinity=all;
js_fetch_trusted_certificate /path/to/isrg_root_x1.pem;
}
// http.js 定时任务函数
async function periodictask(s) {
try {
// 定时拉取页面并写入日志
let res = await ngx.fetch('https://nginx.org/en/docs/njs/');
let body = await res.text();
ngx.log(ngx.info, `定时任务执行:页面长度 ${body.length}`);
} catch (e) {
ngx.log(ngx.err, `定时任务失败:${e.message}`);
}
}
三、njs 核心对象与常用 api
njs 脚本的核心是请求对象(r) 和全局对象(ngx),以下是高频使用的属性/方法:
1. 请求对象(r):处理请求的核心
| 属性/方法 | 作用 |
|---|---|
| r.method | 获取请求方法(get/post/put 等) |
| r.headersin | 请求头对象(如 r.headersin.host 获取主机名) |
| r.headersout | 响应头对象(设置响应头,如 r.headersout['content-type'] = 'text/plain') |
| r.args | 自动解析的查询参数对象(只读,重复键为数组,自动解码) |
| r.variables | nginx 内置变量(如 r.variables.arg_foo 获取 foo 参数第一个值) |
| r.return(status, body, headers) | 快速返回响应(状态码+内容+响应头) |
| r.sendheader() | 发送响应头(分步构建响应时使用) |
| r.send(data) | 分段发送响应体 |
| r.log(msg) | 写入 nginx 错误日志 |
2. 全局对象(ngx):高级能力入口
| 属性/方法 | 作用 |
|---|---|
| ngx.fetch(url, opts) | 发起 http/https 请求(异步,返回 promise) |
| ngx.shared.zonename | 访问共享字典(如 ngx.shared.mydict.get(key)) |
| ngx.log(level, msg) | 写入日志(level:ngx.info/ngx.err 等) |
| crypto.subtle.digest | 加密哈希(如 sha-512,0.7.0+) |
四、njs 最佳实践与注意事项
1. 版本兼容性
- 优先使用 njs 0.7.0+ 版本,支持异步 await、fetch api、加密等高级特性;
- 旧版 js_include 已废弃,升级为 js_import;
- r.headersout 直接赋值在低版本可能报错,可改用 r.header(key, value)。
2. 性能与安全
- 同步/异步限制:js_set/js_header_filter/js_body_filter 仅支持同步操作,异步需用 js_content + async/await;
- 共享字典优化:设置合理的 timeout 和 evict,避免内存溢出;
- 证书验证:fetch api 调用 https 接口时,务必配置 js_fetch_trusted_certificate,开启 js_fetch_verify on;
- 参数校验:避免直接使用 r.args/r.headersin 中的值,防止注入攻击。
3. 调试技巧
- 开启 nginx 调试日志:error_log /var/log/nginx/error.log debug;;
- 使用 r.log()/ngx.log() 打印关键变量,定位问题;
- 测试异步函数时,确保捕获所有异常,避免 nginx 抛出 500 错误。
总结
njs 是 nginx 从“配置驱动”到“配置+编程驱动”的重要扩展,通过 ngx_http_js_module 模块的丰富指令,可实现请求处理、响应过滤、异步调用、跨进程数据共享、定时任务等核心能力。掌握 njs 的核心指令(js_import/js_content/js_set)、请求对象(r)和全局对象(ngx),能大幅提升 nginx 的灵活性,无需额外部署服务即可完成复杂的网关层逻辑。在实际使用中,需注意版本兼容性和性能优化,结合业务场景合理选择同步/异步方式,确保稳定与高效。
到此这篇关于nginx njs从基础配置到高级特性实战的文章就介绍到这了,更多相关nginx njs内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论