我在 Laravel 中为我的应用程序构建功能时遇到问题,因为它有奇怪的隐式路由模型绑定逻辑。
我为具有隐式绑定模型的管理面板配置了一些路由。示例如下:
Route::get('/admin/books/{book}', BooksController);
我显然还为所有管理路由提供了一个全局中间件,用于检查用户是否已通过管理员身份验证,如果不是管理员,则将其路由到登录页面。
class AuthenticateAdmin
{
public function handle(Request $request, Closure $next): Response
{
dump('inside admin auth middleware');
if (! Auth::user()?->is_admin) {
return to_route('admin.signin');
}
return $next($request);
}
}
我面临的问题是,如果我访问不存在的路线,例如
/admin/books-non-existent
,我会得到正确的重定向,因为中间件确实启动了。也就是说,我收到转储消息。
但是,如果我访问存在的路线,但模型绑定失败,例如
/admin/books/xyz
,中间件根本不会运行!我没有收到任何转储消息。
如何让中间件在路由模型绑定失败时也运行?
出现此问题是因为 Laravel 尝试在运行中间件之前绑定模型。如果模型绑定失败(例如,/admin/books/xyz,其中 xyz 不是有效 ID),它会抛出 ModelNotFoundException,跳过中间件。
解决方案:在Handler.php中捕获异常 在 app/Exceptions/Handler.php 中,您可以处理此异常以确保中间件逻辑仍然运行:
use Illuminate\Database\Eloquent\ModelNotFoundException;
public function render($request, Throwable $exception)
{
if ($exception instanceof ModelNotFoundException) {
if ($request->is('admin/*')) {
if (! Auth::user()?->is_admin) {
return redirect()->route('admin.signin');
}
return redirect()->route('admin.books.index'); // or any fallback route
}
}
return parent::render($request, $exception);
}
说明: Laravel 在中间件之前运行模型绑定,因此当绑定失败时,中间件不会被触发。 通过捕获 Handler.php 中的异常,您可以确保中间件逻辑(如管理检查)在模型绑定失败时仍然运行。 这应该可以解决您的问题!