【问题标题】:Laravel treats optional url parameter as obligatoryLaravel 将可选的 url 参数视为强制性的
【发布时间】:2020-08-02 06:40:42
【问题描述】:

我试图让几个 url 有可选的前缀。 现在我只向该组添加了 2 个 url:基本 url '/' 和测试 url。对于基本网址,一切正常。但是当我尝试访问没有前缀的测试 url 时,我得到 404。 问题可能出在哪里?

这是我的路线/web.php 的一部分

Route::group([
    'prefix' => '{lang?}',
    'where' => ['lang' => '[a-z]{2}'],
    'middleware' => 'localization'
], function () {
    Route::get('/', function () {
        return view('welcome');
    });

    Route::get('/test/me/please', function () {
        return 'Bla Bla Bla';
    });
});

这是php artisan route:list的输出:

+--------+----------+------------------------+------+---------+------------------+
| Domain | Method   | URI                    | Name | Action  | Middleware       |
+--------+----------+------------------------+------+---------+------------------+
|        | GET|HEAD | api/user               |      | Closure | api,auth:api     |
|        | GET|HEAD | {lang?}                |      | Closure | web,localization |
|        | GET|HEAD | {lang?}/test/me/please |      | Closure | web,localization |
+--------+----------+------------------------+------+---------+------------------+

【问题讨论】:

    标签: php laravel laravel-5 laravel-7


    【解决方案1】:

    我在这里看到的唯一问题是中间件。

    我在本地使用'middleware' => 'web' 对其进行了测试,它运行良好。 然后我切换到'middleware' => 'localization',它开始抛出错误。所以我创建了一个新的中间件并再次测试它,但它还没有工作。所以我在$routeMiddleware数组下的App\Http\Kernel中注册了中间件,运行php artisan config:cache,刷新页面,它又可以工作了。

    所以我想注册 localization 中间件应该可以解决问题。

    P.S> 我使用的路线是:.../en/test/me/please。另一个可能的问题可能是您输入了这样的内容:.../enasdf/test/me/please(语言超过 2 个字符)或这个:.../test/me/please/en(末尾的可选参数)。在这些情况下,它会抛出 404 not found。

    玩得开心!

    佩约

    【讨论】:

      【解决方案2】:

      Laravel 只是不喜欢可选前缀,因为它后面有额外的路径,因为它在匹配时会混淆(正如你的代码中所证明的那样,'/' 有效,但其他路径没有)所以你应该在你的在这种情况下,但是还有另一种方法可以实现您想要做的事情,那就是通过指定两个路由,其中​​一个具有必需的 lang 参数,而另一个没有。

      虽然它看起来不漂亮,因为它会使你的路线翻倍,这就是我的结构:

      // Prepare your routes as a closure
      $myRoutes = function(){
          Route::get('/', function () {
              return view('welcome');
          });
      
          Route::get('/test/me/please', function () {
              return 'Bla Bla Bla';
          });
      };
      
      
      // Create a group that will use the middleware if it has the prefix
      Route::group([
            'prefix' => '{lang}',
            'where' => ['lang' => '[a-z]{2}'],
            'middleware' => 'localization'
        ], $myRoutes
      );
      
      // Redefine the routes to handle when there is no lang prefix
      $myRoutes();
      

      这可能对您不起作用,具体取决于您的其他路线的结构

      【讨论】:

        【解决方案3】:

        这是一种解决方法:

        function getSubDomain()
            {
                $host = parse_url(url()->current())['host'];
                $exploded = explode('.', $host);
        
                array_pop($exploded); //remove TLD
                array_pop($exploded); //remove domain
                return $exploded[0] ?? null; //returns null if no subdomain is passed
            }
        

        创建一个中间件将其应用到您的路由组。在中间件中,调用上述函数获取前缀/子域并附加到请求对象例如:

        public function handle($request, Closure $next)
            {
                $subdomain = $this->getSubdomain();
                $request->merge(['subdomain' => $subdomain]);
        
                return $next($request);
            }
        

        有了这个,你可以这样声明你的路线:

        Route::group([
            'middleware' => 'sub.parse' // need to be declared in app/Http/Kernel.php
        ], function () {
            Route::get('/', function () {
                $subdomain = request('subdomain'); // suddomain already available in request object
            });
        
            Route::get('/test/me/please', function () {
                return 'Bla Bla Bla';
            });
        });
        

        因此,无论您需要子域,您都可以从请求对象中获取它,例如 $request->subdomain

        【讨论】:

        • 问题是我不会使用中间件,因为 laravel 无法识别没有前缀的路由。我得到 404 并且无法进入任何中间件。所以,我需要弄清楚如何在不声明所有路由两次的情况下解决这个问题:带前缀和不带前缀
        猜你喜欢
        • 2018-08-18
        • 2014-04-15
        • 1970-01-01
        • 2019-06-15
        • 2021-09-09
        • 2012-08-14
        • 1970-01-01
        • 2022-12-07
        • 1970-01-01
        相关资源
        最近更新 更多