Nginx sub_filter不支持按域名动态启用,但可通过多server块(推荐)、map映射(需sub_filter_recursive on)或避免使用if实现按域名注入不同统计代码,注意Content-Type、Gzip及引号转义。

Nginx 的 sub_filter 本身不支持根据域名动态启用或切换注入内容,它作用于匹配的响应体,且配置是静态的。但你可以通过组合 map、sub_filter 和 if(谨慎使用)或更推荐的多 server 块方式,实现“按域名注入不同统计代码”的效果。
方案一:为每个域名单独配置 server 块(最稳定推荐)
这是最清晰、可维护性最高、兼容性最好的方式。每个域名对应一个独立的 server 块,在其中直接配置专属的 sub_filter 规则:
- 在
server { server_name example.com; }中写入针对 example.com 的统计代码(如百度统计) - 在
server { server_name app.example.net; }中写入另一套(如 GA4 或自建埋点 JS) - 确保
sub_filter_once off;(允许多次替换),sub_filter_types text/html;(覆盖 HTML 响应) - 用
sub_filter '' '你的JS代码';实现精准注入
方案二:用 map + sub_filter(需 Nginx ≥ 1.9.2,较灵活)
利用 map 将域名映射为不同统计代码片段,再在通用 server 块中引用:
- 在
http块顶部定义:
map $host $analytics_js {
default "";
example.com "<script src="//bdstat.com/c.js"></script>";
app.example.net "<script async src="//gtag.js?id=G-XXX"></script>";
}
- 在
server块中启用 sub_filter:
sub_filter '' '$analytics_js'; sub_filter_once off; sub_filter_types text/html;
⚠️ 注意:sub_filter 默认不解析变量(如 $analytics_js),需开启 sub_filter_recursive on;(Nginx ≥ 1.17.5)或改用 sub_filter 多次匹配 + map 控制开关(更稳妥)。
方案三:用 if + sub_filter(不推荐,仅作了解)
if 在 location 中对 sub_filter 生效有限,且 Nginx 官方明确警告 if 在 location 中行为复杂。以下写法不可靠,容易失效或引发缓存/编码问题:
-
if ($host = "example.com") { sub_filter ... }—— 语法错误,sub_filter 不支持条件块 - 试图用
set+if动态赋值再给sub_filter—— 变量不会被展开
结论:避免用 if 驱动 sub_filter,它不是为此设计的。
关键细节与避坑提醒
-
sub_filter只处理响应体,不修改响应头;确保后端返回的是text/html类型(检查Content-Type) - 若页面启用了 Gzip,必须加
sub_filter对应的gzip off;或启用gunzip on;(Nginx ≥ 1.3.12) - 注入 JS 时注意引号转义:单引号包围整个字符串,内部双引号无需反斜杠;如需含单引号,用
\' - 调试技巧:临时加
add_header X-Subfilter-Used "$analytics_js";查看变量是否生效










