Laravel 11+PHP8.2+TwillCMS中404 URL无法通过Web中间件求助
解决Laravel重定向中间件无法处理404请求的问题
问题根源
Laravel的路由中间件(比如你加入web组的中间件)只会在路由匹配成功后执行,而404请求分为两种场景:
- 路由完全未匹配:请求路径没有对应任何路由定义,此时路由中间件不会触发
- 模型绑定失败:比如
show(Page $page)中Page不存在,Laravel会直接抛出ModelNotFoundException并进入异常处理流程,可能跳过你的重定向逻辑
解决方案
方案1:将重定向中间件设为全局中间件
全局中间件会对所有请求生效,无论路由是否匹配。修改bootstrap/app.php:
// 追加到全局中间件列表 $middleware->append(\App\Http\Middleware\Redirector::class);
然后在中间件中添加过滤逻辑,避免影响API等非web请求:
public function handle(Request $request, Closure $next) { // 跳过API路由(根据你的实际路由规则调整) if ($request->is('api/*')) { return $next($request); } // 重定向逻辑:检查数据库中的重定向规则 $redirect = \App\Models\Redirect::where('old_url', $request->path())->first(); if ($redirect) { return redirect()->to($redirect->new_url, $redirect->status_code); } return $next($request); }
方案2:通过异常处理器捕获404场景
如果不想用全局中间件,可在异常处理器中统一处理所有404情况。修改app/Exceptions/Handler.php:
use Illuminate\Database\Eloquent\ModelNotFoundException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; public function register() { // 处理路由未匹配的404 $this->renderable(function (NotFoundHttpException $e, $request) { $redirect = \App\Models\Redirect::where('old_url', $request->path())->first(); if ($redirect) { return redirect()->to($redirect->new_url, $redirect->status_code); } }); // 处理模型绑定失败的404(比如Page找不到) $this->renderable(function (ModelNotFoundException $e, $request) { $redirect = \App\Models\Redirect::where('old_url', $request->path())->first(); if ($redirect) { return redirect()->to($redirect->new_url, $redirect->status_code); } }); }
方案3:修复Fallback路由的使用
如果坚持用Route::fallback(),确保以下几点:
- 将Fallback路由放在
web.php的最后一行,保证它是最后匹配的路由 - 清除路由缓存(如果开启了缓存):
php artisan route:clear - 直接在Fallback闭包中加入重定向逻辑(或确保中间件已正确关联):
// web.php 最后一行 Route::fallback(function (Request $request) { // 先检查重定向 $redirect = \App\Models\Redirect::where('old_url', $request->path())->first(); if ($redirect) { return redirect()->to($redirect->new_url, $redirect->status_code); } // 无重定向则返回404视图 return view("404"); });
方案4:自定义模型绑定逻辑
针对Page模型绑定失败的场景,可在RouteServiceProvider中自定义绑定逻辑:
public function boot() { parent::boot(); Route::bind('page', function ($value) { $page = \App\Models\Page::where('slug', $value)->first(); if (!$page) { // 检查是否有对应重定向 $redirect = \App\Models\Redirect::where('old_url', request()->path())->first(); if ($redirect) { throw new \Illuminate\Http\Exceptions\HttpResponseException( redirect()->to($redirect->new_url, $redirect->status_code) ); } abort(404); } return $page; }); }
内容的提问来源于stack exchange,提问作者Exarillion
相关产品推荐
相关产品推荐

