Laravel 5.5路由名称用env字符串致Route::has()失效问题
解决Laravel 5.5中.env路由名称导致Route::has()失效及访客重定向问题
我来帮你搞定这两个关联的问题,先从Route::has()失效的根源说起,再一步步实现访客路由的重定向逻辑。
一、为什么Route::has()会失效?
Laravel在路由缓存时(运行php artisan route:cache),会把路由定义编译成静态文件,如果你直接在路由里用env('ADMIN_ROUTE')生成路由名称,缓存后这个动态的env变量会被固化成编译时的值,后续即使.env变化或者动态判断时,Route::has()也无法正确匹配到对应的路由名称。
解决方案:用配置文件替代直接调用env
- 创建后台路由配置文件
在config目录下新建admin.php,把.env里的路由配置转移到这里:
return [ 'route_prefix' => env('ADMIN_ROUTE', 'admin'), // 默认值设为admin,避免.env没配置时出错 ];
- 修改路由定义,用config值生成路由名称和前缀
在routes/web.php里这样定义路由:
$adminPrefix = config('admin.route_prefix'); // 后台主路由组(给管理员用) Route::prefix($adminPrefix) ->name("{$adminPrefix}.") // 路由名称前缀,比如admin.jobs ->group(function () { Route::get('jobs', 'Admin\JobController@index')->name('jobs'); // 其他后台路由都按这个格式定义 }); // 访客后台路由组 Route::prefix("{$adminPrefix}/guest") ->name("{$adminPrefix}.guest.") // 访客路由名称前缀,比如admin.guest.jobs ->group(function () { Route::get('jobs', 'Admin\JobController@guestIndex')->name('jobs'); // 对应主后台的每个路由,都在这里创建访客版本 });
这样路由名称都是基于config的静态值生成的,不管有没有缓存,Route::has()都能正常识别,比如Route::has('admin.jobs')或者Route::has('admin.guest.jobs')都会返回正确结果。
二、实现访客重定向的中间件
接下来写一个中间件,自动把访客访问的后台路由重定向到对应的guest路径:
- 生成中间件
运行Artisan命令创建中间件:
php artisan make:middleware RedirectGuestToGuestRoute
- 编写中间件逻辑
打开app/Http/Middleware/RedirectGuestToGuestRoute.php,替换成以下代码:
<?php namespace App\Http\Middleware; use Closure; use Illuminate\Support\Facades\Route; class RedirectGuestToGuestRoute { public function handle($request, Closure $next) { $adminPrefix = config('admin.route_prefix'); $currentPath = $request->path(); // 判断当前请求是否是后台路由,但不是访客路由 if (strpos($currentPath, "{$adminPrefix}/") === 0 && strpos($currentPath, "{$adminPrefix}/guest/") !== 0) { // 提取后台前缀之后的路由部分,比如从/admin/jobs提取jobs $routeSegment = substr($currentPath, strlen($adminPrefix) + 1); // 拼接对应的访客路由名称 $guestRouteName = "{$adminPrefix}.guest.{$routeSegment}"; // 如果访客路由存在,就重定向过去 if (Route::has($guestRouteName)) { return redirect()->route($guestRouteName); } } return $next($request); } }
- 注册中间件
打开app/Http/Kernel.php,在$routeMiddleware数组里添加这个中间件:
protected $routeMiddleware = [ // 其他已有中间件... 'admin.guest.redirect' => \App\Http\Middleware\RedirectGuestToGuestRoute::class, ];
- 给后台路由组应用中间件
回到routes/web.php,把中间件加到主后台路由组上:
Route::prefix($adminPrefix) ->name("{$adminPrefix}.") ->middleware('admin.guest.redirect') // 这里添加中间件 ->group(function () { Route::get('jobs', 'Admin\JobController@index')->name('jobs'); // 其他后台路由 });
最后测试注意事项
- 如果你之前缓存过路由,先清缓存:
php artisan route:clear - 测试时可以先关闭路由缓存(不要运行
route:cache),确认逻辑正常后再缓存 - 确保访客路由和主后台路由的名称后缀一致,比如主路由是
admin.jobs,访客路由必须是admin.guest.jobs,这样中间件才能正确匹配
内容的提问来源于stack exchange,提问作者Quentin B
相关产品推荐
相关产品推荐

