nginx中不推荐在if块中直接用rewrite做地域重定向,应改用geoip2模块获取国家码,再通过map预定义跳转规则,最后用return 301安全触发重定向。

Nginx 中不推荐在 if 块中直接使用 rewrite 实现地理位置重定向,因为 if 在 location 上下文中的行为有诸多限制和陷阱(比如变量未初始化、指令执行顺序异常、重写逻辑被跳过等),容易导致重定向失效或循环跳转。正确做法是结合 geoip 或 ngx_http_geoip2_module 模块获取地域信息,再用 map 预定义跳转规则,最后通过 return 或 rewrite ... permanent 安全触发重定向。
1. 启用地理信息模块(以 geoip2 为例)
现代 Nginx 推荐使用 ngx_http_geoip2_module(需编译安装或通过包管理器启用),它支持 GeoLite2 数据库,精度高、更新及时:
- 下载 GeoLite2 Country/ City 数据库(
GeoLite2-Country.mmdb),放到如/usr/share/GeoIP/ - 在
http块中加载模块并定义变量:geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb { $geoip2_data_country_code source=$remote_addr country iso_code; $geoip2_data_country_name source=$remote_addr country names en; }
2. 用 map 映射地域到目标 URL(安全可靠)
map 指令在配置加载时预计算,无运行时副作用,是替代 if + rewrite 的标准方案:
- 在
http块中定义跳转目标:map $geoip2_data_country_code $redirect_url { default ""; CN "https://cn.example.com$request_uri"; JP "https://jp.example.com$request_uri"; US "https://us.example.com$request_uri"; } - 注意:
$request_uri保留原始路径和参数,避免丢失;空字符串表示不重定向
3. 在 server 或 location 中触发重定向
检查变量非空后直接返回 301,简洁高效:
- 示例配置:
server { listen 80; server_name example.com; <pre class="brush:php;toolbar:false;">if ($redirect_url) { # 此处 if 仅作布尔判断,安全 return 301 $redirect_url; } # 其他正常处理逻辑... root /var/www/html; index index.html;}
- ⚠️ 关键点:这里
if只用于判断变量是否为空(非空即重定向),不嵌套 rewrite、set 或 proxy_pass,规避了 Nginx 的if陷阱 - 也可用
rewrite ^(.*)$ $redirect_url permanent;,但return 301更轻量、语义更清晰
4. 补充:兼容旧版 geoip(已弃用,仅作参考)
若仍在用老的 ngx_http_geoip_module(基于.dat 文件):
- 配置类似:
geoip_country /usr/share/GeoIP/GeoIP.dat; map $geoip_country_code $redirect_url { default ""; CN "https://cn.example.com$request_uri"; } - 注意该模块仅支持国家码,不支持城市/经纬度等细粒度信息,且 GeoIP.dat 已停止更新











