要让 Nginx 的 sub_filter 只处理 CSS 和 JS 文件,关键在于精准声明 MIME 类型(如 text/css、application/javascript、text/javascript),严格隔离作用域(sub_filter 与 sub_filter_types 同配置块),禁用或解压压缩响应,并控制替换范围与缓冲策略。

要让 Nginx 的 sub_filter 真正只处理 CSS 和 JS 文件,关键不是“多配几个类型”,而是**精准声明、严格隔离、避免干扰**。很多性能问题和替换失效,其实源于类型匹配失控或压缩未处理。
只声明必需的 MIME 类型,不碰通配符
sub_filter_types 默认只认 text/html,哪怕你代理的是 .css 文件,只要响应头是 Content-Type: text/css,就必须显式加上它。常见误操作是写 sub_filter_types * 或 text/*——这会让 Nginx 去尝试处理 text/plain、text/csv 甚至 API 返回的 text/x-json,白白消耗 CPU,还可能意外改写非目标内容。
- 只加实际要处理的类型:
text/css application/javascript text/javascript -
application/javascript是现代标准,但旧后端仍可能返回text/javascript,两个都列更稳妥 - 不用
text/*,也不用*;宁可漏掉一类,也不泛滥匹配
确保 sub\_filter 和 sub\_filter\_types 同作用域且成对出现
这两个指令必须出现在同一个配置块里(http、server 或 location),否则 Nginx 会静默忽略。例如:在 http 块里写了 sub_filter_types,但在某个 location 里才写 sub_filter,那这个 location 下的替换根本不会触发 CSS/JS。
- 推荐在
location块内统一配置,便于按路径精细化控制 - 顺序无关,但建议把
sub_filter_types放在sub_filter上方,逻辑更清晰 - 每个需要替换的 location 都应独立声明自己的
sub_filter_types,不要依赖上级继承
禁用压缩或启用解压,保证 sub\_filter 能读到明文
sub_filter 只能处理原始文本。如果后端返回了 gzip 压缩的 CSS 或 JS,Nginx 不会自动解压再过滤——它直接跳过,什么也不做,也不会报错。结果就是你看到文件没变、日志安静如初,却始终不生效。
- 最简单方案:
proxy_set_header Accept-Encoding "";让后端不压缩 - 若必须接收压缩响应,需开启
gunzip on;并确保gunzip_vary on;,让 Nginx 在收到Content-Encoding: gzip时先解压再交给sub_filter - 用
curl -I https://your.domain/style.css检查响应头,确认Content-Type和Content-Encoding符合预期
配合 sub\_filter\_once 和缓冲策略控制开销
全局替换(sub_filter_once off)虽灵活,但对大 JS 文件可能引发内存和延迟问题。尤其当多个 sub_filter 规则叠加时,每行都要扫描多次。
- 对纯路径替换类操作(如 CDN 域名、版本号),优先用单次替换 + 多条规则,比全局扫描更轻量
- 确保
proxy_buffering on;且缓冲区足够(如proxy_buffers 8 128k;),避免流式响应导致部分 body 无法被完整捕获 - 不建议在高并发网关上对 >500KB 的 JS 文件频繁做全文本替换;这类场景更适合构建时注入或 Lua 动态处理










