sub_filter_types 是控制 sub_filter 高效运行的核心开关,需精准声明 text/html、application/json 等必要 mime 类型,禁用 gzip 或启用 gunzip,并按 location 分层配置,避免全局泛化和二进制流无效处理。

要让 sub_filter 在缓存场景下高效运行,核心不是“全量扫描”,而是让替换只发生在真正需要处理的响应上——sub_filter_types 就是这个开关。配得准,CPU 和内存开销就低;配得松,Nginx 会为图片、压缩包、二进制流反复分配缓冲、尝试解码,结果什么也没改,还拖慢整体性能。
只声明明确需要处理的 MIME 类型
默认情况下,sub_filter 只作用于 text/html。如果你要替换 JS 或 CSS 中的域名或版本号,必须显式加上对应类型:
-
text/css:用于处理样式表里的 URL(如@import url("/theme.css")) -
application/javascript和text/javascript:覆盖新旧后端返回的脚本类型 -
application/json:适用于前端配置接口中嵌入的静态资源路径 - 避免写
sub_filter_types *或text/*——它们会让 Nginx 对text/csv、text/plain甚至错误页都做字符串扫描,纯属浪费
确保缓存响应本身可被处理
缓存内容若带 Content-Encoding: gzip,sub_filter 会直接跳过,不报错也不生效。这不是 bug,是设计限制:
- 在 proxy 缓存 location 中,加
gzip off;或proxy_set_header Accept-Encoding "";,让上游返回明文 - 如果必须保留压缩,启用
gunzip on;,但务必同步调小缓冲:sub_filter_buffer_size 256k;,防止解压后内存翻倍 - 检查缓存响应头:
curl -I http://your-site/config.json,确认Content-Type和Content-Encoding符合预期
按 location 分层控制,拒绝全局泛化
把 sub_filter_types 放在 http 块里,等于让所有请求都多一次类型判断和潜在缓冲。正确做法是收窄到具体路径:
- 静态资源路径:
location ~* \.(js|css|html)$ { sub_filter ...; sub_filter_types text/css application/javascript text/html; } - API 配置接口:
location /api/config { sub_filter 'http://dev' 'https://prod'; sub_filter_types application/json; } - 不用的类型坚决不加,比如
image/svg+xml仅在 HTML 内联 SVG 且需替换时才启用
配合缓存策略保持响应头一致性
替换后的内容已变,但原始缓存头(如 ETag、Last-Modified)可能未更新,导致客户端拿到脏数据:
- 加
proxy_hide_header ETag;和add_header Cache-Control "no-cache";,强制绕过强缓存 - 若用
proxy_cache,建议基于未压缩响应建缓存,避免“缓存命中却无法替换”的静默失效 - 开启
sub_filter_once off;确保同一响应内所有匹配项都被处理,尤其适用于批量替换 CDN 域名










