nginx rewrite重写URL地址, laravel路由404问题

前言

在开发项目时,我面临一个需求:区分移动端和桌面端访问路径。移动端访问应在路径前加上/m/,而桌面端则不需要。例如:

  • 移动端: 域名/m/路由地址
  • 桌面端: 域名/路由地址

这种设计在路由规则上带来了一定的重复,因为相同的处理逻辑需要为两种不同的路径配置。例如,原始PHP路由配置如下:

# 不加上m写一次规则
Route::get('/register', 'Auth\RegisterController@showRegistrationForm');
# 加上m写一次规则
Route::get('/m/register', 'Auth\RegisterController@showRegistrationForm');

这导致代码重复,为了解决这个问题,我决定通过Nginx的地址重写功能来优化。

Nginx 配置
我在Nginx配置文件中添加了以下规则,以实现地址重写:

server {
    listen        93;
    server_name  localhost;
    root   "F:/project/work/gameWeb/public/";

    location /m/ {
        rewrite ^/m/(.*)$ /$1 last;    
    }

    location / {
        index index.php index.html error/index.html;
        try_files $uri $uri/ /index.php$is_args$args;
        autoindex  off;
    }

    location ~ \.php(.*)$ {
        fastcgi_pass   127.0.0.1:9002;
        fastcgi_index  index.php;
        fastcgi_split_path_info  ^((?U).+\.php)(/?.+)$;
        fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
        fastcgi_param  PATH_INFO  $fastcgi_path_info;
        fastcgi_param  PATH_TRANSLATED  $document_root$fastcgi_path_info;
        fastcgi_param  REQUEST_URI        $request_uri;
    }
}

尽管Nginx重写规则看似有效,但最终仍返回了Laravel的404页面,说明路由匹配失败。

结论与解决方案

问题出在以下这行配置:

fastcgi_param  REQUEST_URI $request_uri;

在PHP中,$_SERVER[‘REQUEST_URI’] 获取的是重写前的URL,而不是重写后的。意味着即使URL被重写为不含 /m/ 的路径,REQUEST_URI 仍然包含 /m/。

为了验证这一点,我将上述行修改为:

fastcgi_param  REQUEST_URI "/register";

这样,访问 域名/m/register 时,路由规则能成功匹配到:

Route::get('/register', 'Auth\RegisterController@showRegistrationForm');

这表明Laravel的路由匹配实际上是依赖于 REQUEST_URI 的值。因此,要解决这个问题,我觉得不是在于Nginx规则要改写REQUEST_URI,因为这会影响所有的项目。

最终解决方案

在 app\Providers\RouteServiceProvider.php 的代码文件中,修改boot方法
通过加入前缀路由的方式,来去除/m/带来的404问题

public function boot()
    {
        $this->configureRateLimiting();

        $this->routes(function () {
            Route::prefix('api')
                ->middleware('api')
                ->namespace($this->namespace)
                ->group(base_path('routes/api.php'));

            Route::middleware('web')
                ->namespace($this->namespace)
                ->group(base_path('routes/web.php'));
			
			// 不加m的路由
            Route::namespace('App\User\Controller')
                ->group(base_path('routes/user.php'));

			// 加了m的路由,将m视为前缀
            Route::prefix('m')
                ->namespace('App\User\Controller')
                ->group(base_path('routes/user.php'));
        });
    }

补充知识点

框架 laravel/yii2 使用 $_SERVER[‘request_uri’] 中的路径做路由解析,不受rewrite影响
框架 thinkphp 使用 $_SERVER[‘path_info’] 中的路径做路由解析,受rewrite影响
两者最大的不同在于,nginx的rewrite重写后,获取到的路径是截然不同的

在 URL 重写(Rewrite)后的差异

  • REQUEST_URI 变化:当使用 URL 重写(如在 Apache 的 .htaccess 或 Nginx 的 rewrite 规则)时,REQUEST_URI 通常会保持不变,反映原始请求的 URI。
  • PATH_INFO 变化:PATH_INFO 可能会受到 URL 重写的影响。如果 URL 被重写到一个特定的脚本,PATH_INFO 可能会反映重写后的路径。

所以
thinkphp采用nignx的rewrite重写来实现去除/m/的影响理论上可行
但是laravel、YII则不能使用这种方案

这里博主没有去进行测试了

这篇文章可以看看:https://segmentfault.com/a/1190000022499679#item-8

你可能感兴趣的:(nginx,laravel,php)