Nginx 的 sub_filter 指令可实时替换 HTML 响应体中的字符串,将原始资源路径改为 CDN 域名,无需修改后端代码;需确保响应为 text/html 类型、未压缩、正确配置 sub_filter_types 和 proxy_buffer 大小,并注意替换顺序与大小写敏感性。

使用 Nginx 的 sub_filter 指令可以在反向代理响应返回给客户端前,对 HTML(或其他文本类型)内容做实时字符串替换,从而将后端页面中硬编码的原始资源路径(如 https://origin.example.com/static/)动态替换为 CDN 域名(如 https://cdn.example.com/static/)。这无需修改后端代码,适合灰度切换、多环境适配或快速启用 CDN。
确保 sub_filter 生效的基本前提
sub_filter 默认只处理 text/html 类型响应,且仅作用于响应体(body),不修改 header 或二进制内容。需确认以下几点:
- 后端返回的 Content-Type 必须是
text/html(含charset也不影响);若后端返回了application/xhtml+xml等类型,需用sub_filter_types显式添加 - Nginx 需启用
sub_filter模块(默认已编译,无需额外加载) - 响应不能被压缩(gzip/brotli),否则
sub_filter无法解析明文;建议在 proxy 层关闭压缩,或确保后端不返回Content-Encoding: gzip - 替换操作是单次、非正则的字符串替换;如需更复杂逻辑(如匹配域名+路径),需配合多个
sub_filter或改用lua-resty-string等扩展
基础 CDN 链接替换配置示例
假设后端页面中存在:<img src="/static/logo.png" alt="如何利用 sub_filter 指令实现在代理层动态修正后端页面中的 CDN 加速链接" > 或 <script src="https://api.example.com/v1/data.js"></script>,你想统一替换为 CDN 域名:
location / {
proxy_pass https://backend;
proxy_set_header Host $host;
<pre class="brush:php;toolbar:false;"># 关键:关闭响应压缩,避免 sub_filter 失效
proxy_http_version 1.1;
proxy_set_header Accept-Encoding "";
# 替换相对路径静态资源(加 /static/ 前缀)
sub_filter '/static/' '/static/';
sub_filter 'https://origin.example.com/static/' 'https://cdn.example.com/static/';
sub_filter 'http://origin.example.com/static/' 'https://cdn.example.com/static/';
# 支持多轮替换(注意顺序:先换完整 URL,再换相对路径,避免重复干扰)
sub_filter_once off;
# 允许处理 text/plain、application/javascript 等类型(按需添加)
sub_filter_types text/html text/css application/javascript;
# 缓冲区调大,避免截断导致替换失败
proxy_buffer_size 128k;
proxy_buffers 4 256k;
proxy_busy_buffers_size 256k;}
处理 HTTPS 协议自动适配与协议相对链接
为避免硬写 http:// 或 https:// 导致混合内容问题,可采用协议相对 URL 或动态判断:
- 若后端用
//origin.example.com/static/,可直接替换为//cdn.example.com/static/,浏览器自动继承当前页面协议 - 若需强制 HTTPS,统一替换为
https://cdn.example.com/...即可 - 不推荐依赖
$scheme在sub_filter中拼接(它不支持变量插值),但可通过map+add_header辅助生成 JS 变量供前端读取
调试与常见陷阱规避
替换失效时优先检查这几项:
- 用
curl -I确认响应头是否含Content-Encoding: gzip;如有,加proxy_set_header Accept-Encoding ""并确认后端未强制压缩 - 用
curl -s http://your-proxy/ | head -n 50查看原始响应是否含待替换字符串(注意空格、换行、HTML 实体编码等干扰) -
sub_filter区分大小写;若后端混用大小写,需分别定义替换规则,或改用 Lua 模块做正则忽略大小写 - 避免跨标签误替换(例如把
<div> 中的 <code>src也替换了),建议尽量锚定完整路径片段(如src="/static/→src="/static/)不复杂但容易忽略细节,关键是让响应保持可读、未压缩、类型匹配,并控制好替换粒度。上线前务必用真实页面验证所有资源加载路径是否正确指向 CDN。

















