You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

配置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;
        }
    }
}

配置说明

  1. rewrite规则优化:使用break标志替代last,这样Nginx会在当前location内继续处理请求,不会重新匹配其他location,避免了无意义的跳转和404问题。
  2. 覆盖REQUEST_URI:通过fastcgi_param REQUEST_URI $uri$is_args$args;,把改写后的URI传递给PHP,这样$_SERVER['REQUEST_URI']就会变成/api/v0/create,完全符合应用路由的预期。
  3. 多前缀支持:如果有多个类似/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

火山引擎 最新活动