NGINX njs從基礎(chǔ)配置到高級(jí)特性實(shí)戰(zhàn)
一、njs 核心基礎(chǔ):模塊與配置入門
1. 模塊加載與核心定位
ngx_http_js_module 是 njs 的核心模塊,需先在 NGINX 配置中加載(編譯 NGINX 時(shí)需啟用該模塊,或通過動(dòng)態(tài)模塊加載)。njs 主要用于實(shí)現(xiàn)兩類核心能力:
- Location 處理器:接管特定路徑的請(qǐng)求處理(如返回自定義響應(yīng)、調(diào)用外部接口);
- 變量處理器:自定義 NGINX 變量,動(dòng)態(tài)生成變量值。
2. 最簡示例:快速上手
以下是 njs 基礎(chǔ)配置與腳本示例,覆蓋核心用法(適配 njs 0.4.0+ 版本):
步驟 1:NGINX 主配置(nginx.conf)
http {
# 1. 導(dǎo)入 njs 腳本文件(核心指令:js_import)
js_import http.js;
# 2. 自定義 NGINX 變量(js_set 綁定 njs 函數(shù))
js_set $foo http.foo;
js_set $summary http.summary;
server {
listen 8000;
charset utf-8;
# 3. 自定義 content 處理器(js_content 綁定 njs 函數(shù))
location / {
add_header X-Foo $foo; # 使用自定義變量
js_content http.baz; # 接管響應(yīng)內(nèi)容
}
# 直接返回自定義變量值
location = /summary {
return 200 $summary;
}
# 簡單的文本響應(yīng)
location = /hello {
js_content http.hello;
}
}
}
步驟 2:njs 腳本文件(http.js)
// 1. 自定義變量處理器:返回固定值
function foo(r) {
r.log("執(zhí)行 foo 變量處理器"); // 寫入 NGINX 日志
return "foo-value";
}
// 2. 自定義變量處理器:生成請(qǐng)求摘要信息
function summary(r) {
let s = "請(qǐng)求摘要信息\n\n";
// 讀取請(qǐng)求對(duì)象(r)的核心屬性
s += "請(qǐng)求方法:" + r.method + "\n";
s += "HTTP 版本:" + r.httpVersion + "\n";
s += "請(qǐng)求主機(jī):" + r.headersIn.host + "\n";
s += "客戶端IP:" + r.remoteAddress + "\n";
s += "請(qǐng)求URI:" + r.uri + "\n";
// 遍歷請(qǐng)求頭
s += "請(qǐng)求頭:\n";
for (let h in r.headersIn) {
s += ` ${h}: ${r.headersIn[h]}\n`;
}
// 遍歷查詢參數(shù)(r.args 自動(dòng)解析 URL 查詢字符串)
s += "查詢參數(shù):\n";
for (let a in r.args) {
s += ` ${a}: ${r.args[a]}\n`;
}
return s;
}
// 3. 自定義 content 處理器:分步構(gòu)建響應(yīng)
function baz(r) {
r.status = 200; // 設(shè)置響應(yīng)狀態(tài)碼
// 設(shè)置響應(yīng)頭
r.headersOut['Content-Type'] = "text/plain; charset=utf-8";
r.headersOut['Content-Length'] = 15;
// 發(fā)送響應(yīng)頭
r.sendHeader();
// 分段發(fā)送響應(yīng)體
r.send("nginx");
r.send("java");
r.send("script");
// 結(jié)束響應(yīng)
r.finish();
}
// 4. 簡化的響應(yīng)方式:直接返回狀態(tài)碼+內(nèi)容
function hello(r) {
r.return(200, "Hello njs!");
}
// 導(dǎo)出函數(shù)(供 NGINX 配置調(diào)用)
export default { foo, summary, baz, hello };
測(cè)試驗(yàn)證
- 訪問 http://localhost:8000/hello:返回 Hello njs!;
- 訪問 http://localhost:8000/summary?name=test&age=20:返回包含請(qǐng)求方法、頭信息、查詢參數(shù)的摘要文本;
- 訪問 http://localhost:8000/:返回 nginxjavascript(分段發(fā)送的內(nèi)容拼接),響應(yīng)頭包含 X-Foo: foo-value。
二、njs 核心指令詳解
njs 的能力通過一系列專屬指令實(shí)現(xiàn),以下是高頻使用的核心指令分類說明:
1. 腳本導(dǎo)入與基礎(chǔ)指令
| 指令 | 作用 | 適用版本 |
|---|---|---|
| js_import | 導(dǎo)入 njs 模塊(支持命名空間),替代舊版 js_include | 0.4.0+ |
| js_content | 將 njs 函數(shù)設(shè)為 location 內(nèi)容處理器,接管請(qǐng)求響應(yīng) | 全版本 |
| js_set | 將 njs 函數(shù)綁定到 NGINX 變量,函數(shù)返回值作為變量值 | 全版本 |
| js_path | 設(shè)置 njs 模塊的額外加載路徑 | 0.3.0+ |
| js_var | 聲明可寫的 NGINX 變量(重定向后不重置) | 0.5.3+ |
關(guān)鍵說明:
- js_import 支持兩種寫法:
js_import http.js; # 以文件名作為命名空間(http.函數(shù)名) js_import myHttp from http.js; # 自定義命名空間(myHttp.函數(shù)名)
- js_include 已被廢棄(0.7.1 移除),優(yōu)先使用 js_import。
2. 響應(yīng)過濾指令(修改響應(yīng)內(nèi)容/頭)
| 指令 | 作用 | 適用版本 |
|---|---|---|
| js_header_filter | 設(shè)置響應(yīng)頭過濾器,修改/刪除響應(yīng)頭(如清除 Content-Length) | 0.5.1+ |
| js_body_filter | 設(shè)置響應(yīng)體過濾器,逐塊修改響應(yīng)內(nèi)容(如大小寫轉(zhuǎn)換、內(nèi)容替換) | 0.5.2+ |
實(shí)戰(zhàn)示例:響應(yīng)體小寫轉(zhuǎn)換
# NGINX 配置
location /filter {
proxy_pass http://localhost:8080;
# 清除 Content-Length(避免長度不匹配)
js_header_filter http.clearContentLength;
# 響應(yīng)體過濾器:轉(zhuǎn)小寫
js_body_filter http.lowercaseFilter;
}
// http.js 新增函數(shù)
function clearContentLength(r) {
delete r.headersOut['Content-Length'];
}
function lowercaseFilter(r, data, flags) {
// 逐塊處理響應(yīng)體,轉(zhuǎn)小寫后傳遞給下一個(gè)過濾器
r.sendBuffer(data.toLowerCase(), flags);
}
3. Fetch API 相關(guān)指令(0.7.0+)
njs 0.7.0 新增 ngx.fetch 方法,支持發(fā)起 HTTP/HTTPS 請(qǐng)求,配套指令用于配置請(qǐng)求規(guī)則:
| 指令 | 作用 |
|---|---|
| js_fetch_trusted_certificate | 指定 HTTPS 證書驗(yàn)證的可信 CA 文件(PEM 格式) |
| js_fetch_verify | 啟用/禁用 HTTPS 證書驗(yàn)證(生產(chǎn)環(huán)境建議開啟) |
| js_fetch_timeout | 設(shè)置 Fetch 請(qǐng)求的讀寫超時(shí)時(shí)間(默認(rèn) 60s) |
| js_fetch_proxy | 配置 Fetch 請(qǐng)求的正向代理(支持 HTTP 代理,0.9.4+) |
| js_fetch_keepalive | 啟用 Fetch 連接池,設(shè)置最大空閑連接數(shù)(0.9.2+) |
實(shí)戰(zhàn)示例:異步調(diào)用外部接口
# NGINX 配置
location = /fetch {
js_content http.fetch;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
js_fetch_keepalive 32; # 連接池最大空閑連接數(shù)
}
// http.js 新增異步函數(shù)
async function fetch(r) {
try {
// 并行調(diào)用兩個(gè)接口
let results = await Promise.all([
ngx.fetch('https://nginx.org/'),
ngx.fetch('https://nginx.org/en/')
]);
// 解析響應(yīng)并返回
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, `請(qǐng)求失敗:${e.message}`);
}
}
4. 高級(jí)特性指令
4.1 共享字典(0.8.0+):跨 worker 進(jìn)程共享數(shù)據(jù)
# NGINX 配置:創(chuàng)建 1MB 共享字典,60s 超時(shí),支持淘汰舊數(shù)據(jù) js_shared_dict_zone zone=myDict:1M timeout=60s evict;
// http.js 操作共享字典
function setDict(r) {
// 設(shè)置鍵值對(duì)
let result = ngx.shared.myDict.set(r.args.key, r.args.value);
r.return(200, `設(shè)置結(jié)果:${result}`);
}
function getDict(r) {
// 獲取鍵值對(duì)
let value = ngx.shared.myDict.get(r.args.key);
r.return(200, `獲取結(jié)果:${value || '不存在'}`);
}
4.2 定時(shí)任務(wù)(0.8.1+):周期性執(zhí)行函數(shù)
# NGINX 配置:每分鐘在所有 worker 進(jìn)程執(zhí)行定時(shí)任務(wù)
location @periodic {
js_periodic http.periodicTask interval=60s worker_affinity=all;
js_fetch_trusted_certificate /path/to/ISRG_Root_X1.pem;
}
// http.js 定時(shí)任務(wù)函數(shù)
async function periodicTask(s) {
try {
// 定時(shí)拉取頁面并寫入日志
let res = await ngx.fetch('https://nginx.org/en/docs/njs/');
let body = await res.text();
ngx.log(ngx.INFO, `定時(shí)任務(wù)執(zhí)行:頁面長度 ${body.length}`);
} catch (e) {
ngx.log(ngx.ERR, `定時(shí)任務(wù)失?。?{e.message}`);
}
}
三、njs 核心對(duì)象與常用 API
njs 腳本的核心是請(qǐng)求對(duì)象(r) 和全局對(duì)象(ngx),以下是高頻使用的屬性/方法:
1. 請(qǐng)求對(duì)象(r):處理請(qǐng)求的核心
| 屬性/方法 | 作用 |
|---|---|
| r.method | 獲取請(qǐng)求方法(GET/POST/PUT 等) |
| r.headersIn | 請(qǐng)求頭對(duì)象(如 r.headersIn.host 獲取主機(jī)名) |
| r.headersOut | 響應(yīng)頭對(duì)象(設(shè)置響應(yīng)頭,如 r.headersOut['Content-Type'] = 'text/plain') |
| r.args | 自動(dòng)解析的查詢參數(shù)對(duì)象(只讀,重復(fù)鍵為數(shù)組,自動(dòng)解碼) |
| r.variables | NGINX 內(nèi)置變量(如 r.variables.arg_foo 獲取 foo 參數(shù)第一個(gè)值) |
| r.return(status, body, headers) | 快速返回響應(yīng)(狀態(tài)碼+內(nèi)容+響應(yīng)頭) |
| r.sendHeader() | 發(fā)送響應(yīng)頭(分步構(gòu)建響應(yīng)時(shí)使用) |
| r.send(data) | 分段發(fā)送響應(yīng)體 |
| r.log(msg) | 寫入 NGINX 錯(cuò)誤日志 |
2. 全局對(duì)象(ngx):高級(jí)能力入口
| 屬性/方法 | 作用 |
|---|---|
| ngx.fetch(url, opts) | 發(fā)起 HTTP/HTTPS 請(qǐng)求(異步,返回 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 最佳實(shí)踐與注意事項(xiàng)
1. 版本兼容性
- 優(yōu)先使用 njs 0.7.0+ 版本,支持異步 await、Fetch API、加密等高級(jí)特性;
- 舊版 js_include 已廢棄,升級(jí)為 js_import;
- r.headersOut 直接賦值在低版本可能報(bào)錯(cuò),可改用 r.header(key, value)。
2. 性能與安全
- 同步/異步限制:js_set/js_header_filter/js_body_filter 僅支持同步操作,異步需用 js_content + async/await;
- 共享字典優(yōu)化:設(shè)置合理的 timeout 和 evict,避免內(nèi)存溢出;
- 證書驗(yàn)證:Fetch API 調(diào)用 HTTPS 接口時(shí),務(wù)必配置 js_fetch_trusted_certificate,開啟 js_fetch_verify on;
- 參數(shù)校驗(yàn):避免直接使用 r.args/r.headersIn 中的值,防止注入攻擊。
3. 調(diào)試技巧
- 開啟 NGINX 調(diào)試日志:error_log /var/log/nginx/error.log debug;;
- 使用 r.log()/ngx.log() 打印關(guān)鍵變量,定位問題;
- 測(cè)試異步函數(shù)時(shí),確保捕獲所有異常,避免 NGINX 拋出 500 錯(cuò)誤。
總結(jié)
njs 是 NGINX 從“配置驅(qū)動(dòng)”到“配置+編程驅(qū)動(dòng)”的重要擴(kuò)展,通過 ngx_http_js_module 模塊的豐富指令,可實(shí)現(xiàn)請(qǐng)求處理、響應(yīng)過濾、異步調(diào)用、跨進(jìn)程數(shù)據(jù)共享、定時(shí)任務(wù)等核心能力。掌握 njs 的核心指令(js_import/js_content/js_set)、請(qǐng)求對(duì)象(r)和全局對(duì)象(ngx),能大幅提升 NGINX 的靈活性,無需額外部署服務(wù)即可完成復(fù)雜的網(wǎng)關(guān)層邏輯。在實(shí)際使用中,需注意版本兼容性和性能優(yōu)化,結(jié)合業(yè)務(wù)場(chǎng)景合理選擇同步/異步方式,確保穩(wěn)定與高效。
到此這篇關(guān)于NGINX njs從基礎(chǔ)配置到高級(jí)特性實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)NGINX njs內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Nginx配置統(tǒng)計(jì)流量帶寬請(qǐng)求及記錄實(shí)時(shí)請(qǐng)求狀態(tài)的方法
這篇文章主要介紹了Nginx中配置統(tǒng)計(jì)流量帶寬請(qǐng)求及記錄實(shí)時(shí)請(qǐng)求狀態(tài)的方法,分別用到了ngx_req_status和ngx_realtime_request模塊,需要的朋友可以參考下2016-01-01
Nginx實(shí)現(xiàn)動(dòng)靜分離的示例代碼
這篇文章主要介紹了Nginx實(shí)現(xiàn)動(dòng)靜分離的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
Nginx配置location+rewrite實(shí)現(xiàn)隱性域名配置
本文主要介紹了Nginx配置location+rewrite實(shí)現(xiàn)隱性域名配置,包括基于根目錄、條件和反向代理+rewrite配置的隱性域名實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2025-03-03
nginx代理去掉URL前綴的實(shí)現(xiàn)方法
nginx作為一款廣泛使用的反向代理服務(wù)器,在實(shí)際應(yīng)用中,經(jīng)常需要去掉代理請(qǐng)求中的前綴,下面這篇文章主要給大家介紹了關(guān)于nginx代理去掉URL前綴的實(shí)現(xiàn)方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
Windows Server 2016 MySQL數(shù)據(jù)庫安裝配置詳細(xì)安裝教程
這篇文章主要介紹了Windows Server 2016 MySQL數(shù)據(jù)庫安裝配置詳細(xì)安裝教程,需要的朋友可以參考下2017-08-08

