配置Nginx移除URI前缀并让PHP应用获取正确路由路径的方法咨询
配置Nginx移除URI前缀并让PHP应用获取正确路由路径的方法咨询
问题场景
我遇到了一个Nginx配置的棘手问题:我的应用路由期望接收的URI是/api/v0/create,但实际用户请求的地址是http://my-server.test/subdir/api/v0/create,需要Nginx自动去掉URI里的/subdir前缀,让应用的路由器能拿到正确的路径。而且不能用重定向方案,因为还有类似http://my-server.test/anothersubdir/api/v0的请求——它们带有不同的前缀,但核心API路径是一致的。
之前尝试过的配置要么返回Nginx层面的404(不是应用返回的),要么应用仍然能拿到带/subdir的URI,导致路由匹配失败。下面是我当前的完整Nginx配置:
# configuration file /etc/nginx/conf.d/php.conf: server { listen 80; server_name my-server.test; root /var/www; location /subdir/api/ { rewrite ^/subdir(.*)$ $1 last; try_files $uri $uri/ /subdir/api/public/index.php$is_args$args; location ~* \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; } } }
问题分析
你之前的配置有两个核心问题:
rewrite使用了last标志,这会让Nginx重新发起一次location匹配,导致后续的try_files和内部PHP location块可能不生效,直接触发了其他规则返回404。- 没有修改传递给PHP的
REQUEST_URI参数——默认情况下,Nginx会把原始请求的URI传给PHP,所以即便你内部改写了URI,$_SERVER['REQUEST_URI']仍然是带/subdir的版本,导致应用路由判断错误。
解决方案
调整你的Nginx配置,重点解决上述两个问题,以下是修改后的可用配置:
server { listen 80; server_name my-server.test; root /var/www; # 处理/subdir/api路径 location /subdir/api/ { # 改写URI,去掉/subdir前缀,用break保持在当前location内处理 rewrite ^/subdir(/api/.*)$ $1 break; # 先尝试访问静态文件,找不到则交给PHP入口文件 try_files $uri $uri/ /subdir/api/public/index.php$is_args$args; location ~* \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; include fastcgi_params; # 关键:手动设置REQUEST_URI为改写后的路径,确保PHP拿到正确的路由 fastcgi_param REQUEST_URI $uri$is_args$args; # 确保脚本文件路径正确指向实际的PHP入口 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; } } # 如果需要处理anothersubdir/api,复制上述location块修改前缀即可 location /anothersubdir/api/ { rewrite ^/anothersubdir(/api/.*)$ $1 break; try_files $uri $uri/ /anothersubdir/api/public/index.php$is_args$args; location ~* \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; include fastcgi_params; fastcgi_param REQUEST_URI $uri$is_args$args; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $fastcgi_script_name; } } }
配置说明
- rewrite规则优化:使用
break标志替代last,这样Nginx会在当前location内继续处理请求,不会重新匹配其他location,避免了无意义的跳转和404问题。 - 覆盖REQUEST_URI:通过
fastcgi_param REQUEST_URI $uri$is_args$args;,把改写后的URI传递给PHP,这样$_SERVER['REQUEST_URI']就会变成/api/v0/create,完全符合应用路由的预期。 - 多前缀支持:如果有多个类似
/anothersubdir/api的路径,直接复制对应的location块修改前缀即可,每个块独立处理自己的前缀移除逻辑,逻辑清晰易维护。
如果你的多个前缀对应的是同一个PHP应用,也可以用正则location来简化配置,减少重复代码:
location ~ ^/(subdir|anothersubdir)/api/ { # 捕获前缀和API路径部分 rewrite ^/([^/]+)(/api/.*)$ $2 break; # 保存前缀变量,用于定位PHP入口文件 set $app_prefix $1; try_files $uri $uri/ /$app_prefix/api/public/index.php$is_args$args; location ~* \.php$ { fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass php:9000; include fastcgi_params; fastcgi_param REQUEST_URI $uri$is_args$args; fastcgi_param SCRIPT_FILENAME $document_root/$app_prefix/api/public/index.php; fastcgi_param SCRIPT_NAME /$app_prefix/api/public/index.php; } }
这样就可以用一个location块处理所有符合/xxx/api/格式的请求,配置更简洁。
备注:内容来源于stack exchange,提问作者hangerer




