Nginx的sub_filter模块可在响应返回前对文本内容做字符串替换,需配合location使用,且必须关闭gzip、明确Content-Type、启用sub_filter并确保响应为纯文本。

Nginx 的 sub_filter 模块可用于在响应返回给客户端前,对 HTML(或其他文本类型)内容进行简单字符串替换。它必须配合 location 块使用,且仅对 text/html、text/css、application/javascript 等明确指定的 MIME 类型生效(默认只处理 text/html)。关键前提是:响应体必须是流式可缓存的纯文本,不能是 gzip 压缩后的内容(除非用 sub_filter_once off 配合 gzip off),也不能是 chunked 编码未结束的流。
确保 sub_filter 生效的基本条件
以下配置项缺一不可:
-
关闭响应压缩:在对应 location 中显式设置
gzip off;,否则sub_filter无法处理已压缩的字节流; -
明确设置 Content-Type:若上游返回未带
Content-Type或类型不匹配,需用sub_filter_types扩展支持类型,例如:sub_filter_types text/html text/css application/javascript;; -
启用 sub_filter:至少配置一对
sub_filter old_string new_string;,且sub_filter_once off;可实现全局多次替换(默认只替换第一个匹配); -
location 必须能代理或返回文本响应:通常搭配
proxy_pass或alias/root提供静态 HTML 文件。
典型 location + sub_filter 配置示例
以下是一个将后端返回页面中所有 http://old.example.com 替换为 https://new.example.com 的完整 location 示例:
location /app/ {
proxy_pass https://backend-server/;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;"># 关键:关闭压缩,否则 sub_filter 不生效
gzip off;
# 允许对 HTML 和 JS 中的链接做替换
sub_filter_types text/html application/javascript;
sub_filter 'http://old.example.com' 'https://new.example.com';
sub_filter 'http://old-api.example.com' 'https://new-api.example.com';
sub_filter_once off;
# 可选:修正响应头,避免浏览器缓存旧内容
sub_filter_last_modified on;
add_header Last-Modified "";}
常见失效原因与调试方法
如果替换没生效,按顺序检查:
-
查看响应头:用
curl -I确认Content-Encoding: gzip是否存在 —— 存在则必须加gzip off;; -
确认 Content-Type:用
curl -s -D - http://... | head -n 20查看实际返回的Content-Type,确保它在sub_filter_types列表中; -
检查大小写与空格:sub_filter 默认区分大小写且匹配原始字节,
"Old"≠"old",前后空格、换行符都需完全一致; - 避免正则陷阱:sub_filter 不支持正则表达式,只做固定字符串替换;如需更灵活处理,应改用 OpenResty 或应用层解决。
限制与替代建议
sub_filter 功能轻量但局限明显:
- 不支持正则、不支持上下文感知(如只替换 script 标签内内容);
- 无法修改 HTML 结构(如增删标签)、无法处理 base64 或转义字符;
- 对大文件或高并发场景性能开销略高(逐字节扫描);
- 若需复杂重写,推荐在应用侧完成,或使用 Nginx + Lua(OpenResty)做 DOM 级处理。











