从Apache迁移至Nginx时,$_GET参数处理差异问题排查
Apache 转 Nginx 重写规则适配问题及优化方案
原Apache环境.htaccess规则
<ifmodule mod_rewrite.c> RewriteEngine on RewriteBase / RewriteRule ^$ index.php [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond $1 !^(index\.php|admin|captcha|print|pdf\.php|robots\.txt) RewriteRule (.*) index.php?req=$1 [QSA,L] </ifmodule>
最初Nginx配置的问题
一开始用了下面的location配置,多数页面正常,但带查询字符串的内部页面失效:
location / { try_files $uri /index.php?req=$uri$is_args$args; }
问题现象对比
- Apache环境下的
$_GET结果:
array(2) { ["req"]=> string(8) "checkout" ["quick"]=> string(23) "email@address.com" }
- Nginx环境下的
$_GET结果:
array(1) { ["req"]=> string(39) "/checkout?quick=email@address.com" }
可以看到Nginx把完整的请求路径(包括查询字符串)都塞进了req参数里,导致后端无法正确解析独立的查询参数。
临时解决方案(繁琐)
之前手动逐个配置无需重写的路径,但需要维护大量location块,非常麻烦:
location / { try_files $uri $uri/ /index.php?$is_args$args; rewrite ^/(.*)$ /index.php?req=$1 last; } location /admin { try_files $uri $uri/ /admin/index.php?$is_args$args; } location /js/ { # Do nothing. nginx will serve files as usual. } location /css/ { # Do nothing. nginx will serve files as usual. } location /images/ { # Do nothing. nginx will serve files as usual. }
优化后的Nginx配置
直接对应原Apache的规则逻辑,无需逐个添加排除路径:
location / { # 处理根路径直接跳转到index.php if ($uri = '/') { rewrite ^ /index.php last; } # 优先检查文件/目录是否存在,存在则直接返回 try_files $uri $uri/ @rewrite; } location @rewrite { # 匹配原Apache规则里的排除路径,跳过重写 if ($uri ~* ^/(index\.php|admin|captcha|print|pdf\.php|robots\.txt)) { return 404; } # 重写请求并保留原始查询字符串,等价于Apache的QSA标志 rewrite ^/(.*)$ /index.php?req=$1$is_args$args last; } # 单独处理admin路径,保证其内部页面正常解析 location /admin { try_files $uri $uri/ /admin/index.php?$is_args$args; }
配置说明
- 用
try_files先校验真实文件/目录,避免对已存在资源做无效重写 - 用命名location
@rewrite统一管理重写逻辑,结构更清晰 - 通过
if匹配原Apache的排除规则,一次性跳过无需重写的路径 - 重写时用
$is_args$args保留原始查询字符串,和Apache的QSA效果一致 - 单独配置
/admin块,适配其内部的页面解析逻辑
内容的提问来源于stack exchange,提问作者Liam McArthur
相关产品推荐
相关产品推荐

