原生njs需用js_content接管响应,在subrequest获取原始体后剔除指定前缀(如###行),再调用zlib.gzipsync同步压缩并设content-encoding: gzip,但不适用于大响应或高并发场景。

可以通过 NJS(NGINX JavaScript)在 ngx_http_gzip_module 基础上实现对特定前缀的响应体动态剔除,再交由 gzip 压缩——但需注意:NJS 本身不直接干预 gzip 流程,而是通过修改响应体(r.responseBody)或响应头,在压缩前完成内容裁剪。
明确执行时机:必须在压缩前操作响应体
NGINX 的 gzip 压缩发生在输出过滤阶段(output filter),而 NJS 的 body_filter 钩子是在该阶段中执行的,但它运行在 gzip filter 之后(即处理的是已压缩后的二进制流),无法用于“剔除明文再压缩”。因此正确路径是:
- 使用
header_filter或access阶段不可行(尚未生成 body) - 应使用
body_filter的 早期变体:即配合subrequest+return或改用js_body_filter(OpenResty 扩展)不适用原生 NJS - 更可行方案:在
content_by_lua(若用 OpenResty)或改用js_content+ 同步获取原始内容并重写 -
原生 NJS 推荐做法:用
js_content函数接管响应生成,手动读取后端响应(如 subrequest)、剔除指定前缀、设置Content-Encoding: gzip并调用zlib.deflate()——但需自行压缩,失去 nginx gzip 模块的流式/分块优化
利用 subrequest 获取原始响应并剔除前缀
在 js_content 中发起内部子请求,拿到原始响应体后做字符串处理:
- 定义要剔除的前缀,例如
"X-DEBUG-INFO: ...\n"或匹配^#.*$行首注释 - 用
String.prototype.replace()或split().filter()清洗,注意保留换行与编码一致性(UTF-8) - 清洗后设置
r.headersOut['Content-Type']和r.status = 200 - 若需 gzip,可设
r.headersOut['Content-Encoding'] = 'gzip'并调用zlib.gzipSync(body)(NJS v0.8.4+ 支持)
配置示例(nginx.conf + njs.js)
在 http 块中加载脚本:
js_import /path/to/strip_prefix.js;
location /api/ {
js_content strip_prefix.handler;
}
对应 strip_prefix.js:
export default {
handler(r) {
r.subrequest('/upstream', { method: 'GET' })
.then(res => {
if (res.status === 200 && res.responseBody) {
let body = res.responseBody;
// 剔除以 "###" 开头的调试行
body = body.split('
')
.filter(line => !line.trim().startsWith('###'))
.join('
');
// 可选:启用 gzip 压缩(需 zlib)
const compressed = zlib.gzipSync(body);
r.headersOut['Content-Encoding'] = 'gzip';
r.headersOut['Content-Length'] = compressed.length;
r.return(200, compressed);
} else {
r.return(res.status, res.responseBody);
}
})
.catch(e => r.return(500, 'Subrequest failed'));
}
};
注意事项与限制
原生 NJS 对大响应体处理需谨慎:
-
subrequest默认缓冲整个响应体,不适用于 GB 级响应;此时应改用流式 proxy_buffering + 自定义 filter 模块(非 NJS 能力范围) -
zlib.gzipSync()是同步阻塞调用,高并发下可能影响性能;生产建议仅用于中小响应( - 剔除逻辑需兼容编码:确保输入为字符串而非 Buffer(
res.responseBody默认是 string,除非设置了buffering: false) - 若原始响应含 chunked transfer-encoding,subrequest 会自动聚合,无需额外处理











