DEBUG.WIKI
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS
IPPeak:从目标地区访问网页,住宅代理、SEO 监测、广告验证
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国

Nginx sub_filter 没有替换内容,检查上游是否仍返回 gzip

带 gzip 请求时替换不生效,先看上游是否已压缩,再检查编码协商、响应类型与过滤规则继承。

同一个页面,不带 Accept-Encoding: gzip 时字符串替换生效,带上后原文却保持不变。先看上游交给 Nginx 的正文是否已经压缩。sub_filter 匹配响应正文中的字符串,上游已经把 HTML 变成 gzip 字节流时,它不能直接在其中找到原来的文本。

这项限制在 Nginx 1.10.1 的代理场景中就已存在,不能仅因压缩请求失败而认定是某次升级引入的缺陷。不过,压缩只是其中一个分支:响应类型、实际匹配字符串、命中的配置层级和模块是否可用,也要核对。

检查的是上游响应,不只是浏览器收到的响应

记录失败 URL、最终处理它的 location、上游 Content-Type 和 Content-Encoding,再查看实际正文。浏览器能显示正常页面,可能是浏览器已经解压,并不证明 sub_filter 收到的是明文。

Nginx 对客户端做下游 gzip,与上游先压缩再交给 Nginx,是两个不同位置的处理。最终响应带 gzip,不足以判断过滤前的正文是否压缩;应结合上游响应及代理配置核对。

用 curl 查看文本时,也要区分手工声明接受 gzip 与自动解码。需要理解这项对照时,可先看curl 接收 gzip 正文的检查方法。客户端解压只能帮助读出最终内容,不会倒过来替 Nginx 完成过滤前的解压。

让目标上游返回可替换的正文

上游正常遵守编码协商时,可以在目标代理位置省略发给上游的 Accept-Encoding。以下只表示应合入的指令,不是完整 location:

proxy_set_header Accept-Encoding "";

空值使该请求头不再发送给上游。它只改变目标代理请求的编码协商,不保证上游一定停止压缩;如果上游仍固定返回 gzip,就需要调整那个上游的响应编码方式,或明确设计过滤前的解压路径。

新增这一行前,检查该层已有的整组 proxy_set_header。当前层定义了自己的指令后,不会继续整组继承父层的设置;必要的 Host、认证相关头和其他业务头应在实际配置中保持。不要只粘贴这一行,造成另一个请求路由或授权故障。

gunzip on 也不是所有请求都强制解压的开关:Nginx 的 gunzip 模块主要面向不支持 gzip 的客户端,模块本身还需要对应构建支持。客户端已经声明支持 gzip 时,不能假定加了它就一定让 sub_filter 匹配明文。更不能只删掉响应的 Content-Encoding,留下仍被压缩的字节流。

已经是明文,再查类型和匹配条件

sub_filter_types 默认针对 text/html;其他类型需要按真实响应选择配置。不要为省事写成匹配所有 MIME 类型,避免对二进制或其他不适合替换的正文应用规则。

字符串匹配忽略大小写,但仍需检查上游实际输出的形式:URL 编码、HTML 转义或脚本拼接后的文本可能与配置不同。sub_filter_once 默认是 on,每个目标字符串只替换一次;确实需要替换全部出现位置时,再选择 off。

同一层可以有多个 sub_filter,当前层定义了自己的规则后,不会继续继承父层那一组。还应确认运行的 Nginx 具备 http_sub_module;它不是默认构建模块。返回头里的 Location 重写属于另一种操作,不能用正文过滤去代替它。

保存原配置,检查目标实例的配置后再加载。验证上游编码符合预期,目标文本已在实际响应中替换,且响应类型、编码头及缓存行为一致。正文改变后的缓存校验也要检查,不能仅让浏览器靠旧缓存显示一个看似正确的页面。出现回归时恢复该代理位置的原配置,再检查并加载;上游和下游的编码条件应一并恢复核对。