nginx 中推荐优先使用 map 指令处理 ua 分类,仅对极简操作(如单条 return 或 add_header)才安全使用 if;if 不支持 proxy_pass、location、include 等指令,且不可嵌套。

Nginx 中不推荐在 server 或 location 块中直接使用 if 进行复杂逻辑判断(尤其是涉及重写、跳转等),但针对简单的 UA 判断(如屏蔽爬虫、适配移动端、区分桌面端),可以安全使用 if ($http_user_agent ~* pattern) { ... } 形式。
用 if 匹配 UA 的基本语法
UA 信息通过内置变量 $http_user_agent 获取,注意它是小写加下划线的格式(http_user_agent),且默认已自动解码。匹配时建议加 *i(忽略大小写):
-
if ($http_user_agent ~* "mobile") { ... }—— 包含 mobile(不区分大小写) -
if ($http_user_agent ~* "(android|iphone|ipad)") { ... }—— 匹配常见移动端关键词 -
if ($http_user_agent !~* "curl|wget") { ... }—— 排除工具类 UA
常见实用场景与写法
屏蔽恶意爬虫或扫描器:
if ($http_user_agent ~* "(sqlmap|nikto|wget|curl|harvest|acunetix)") {
return 403;
}
将移动设备重定向到 m. 子域(需配合 rewrite):
if ($http_user_agent ~* "(android|iphone|ipad|windows phone|blackberry)") {
rewrite ^(.*)$ https://m.example.com$1 permanent;
}
为微信内置浏览器设置特殊响应头:
if ($http_user_agent ~* "MicroMessenger") {
add_header X-Wechat-Access "true";
}
必须注意的限制和坑
if 在 Nginx 中属于“上下文受限”指令,不能嵌套,且在 if 块中只允许使用有限指令(如 return、rewrite、set、add_header)。以下写法是非法的:
-
if (...) { proxy_pass http://backend; }——proxy_pass不允许出现在if内 -
if (...) { location /api { ... } }——location不能在if中定义 -
if (...) { include conf.d/rules.conf; }——include不支持
如需更灵活的 UA 分流(例如不同 UA 走不同 upstream),应改用 map 指令预定义变量,再在 proxy_pass 等地方引用。
更健壮的替代方案:用 map 实现 UA 分类
这是官方推荐做法,性能更好、逻辑更清晰、无 if 的副作用:
map $http_user_agent $backend {
default "desktop_backend";
~*[Mm]obile "mobile_backend";
~*[Ww]echat "wechat_backend";
~*android|iphone "mobile_backend";
}
然后在 location 中直接使用:
location / {
proxy_pass http://$backend;
}
不复杂但容易忽略:优先用 map 处理 UA 分支,仅当逻辑极简(如单条 return 或 add_header)时才用 if。











