Exception 从中间件中的控制器捕获异常
我有一个可以抛出异常的laravel控制器和一个捕获该异常的全局中间件。在半伪代码中:Exception 从中间件中的控制器捕获异常,exception,laravel-5,middleware,pipeline,Exception,Laravel 5,Middleware,Pipeline,我有一个可以抛出异常的laravel控制器和一个捕获该异常的全局中间件。在半伪代码中: // App\Controllers\... class Controller { function store() { throw new FormException; // via validation etc, but it's thrown here } } // App\Http\Middleware\... class Middleware { function handle
// App\Controllers\...
class Controller {
function store() {
throw new FormException; // via validation etc, but it's thrown here
}
}
// App\Http\Middleware\...
class Middleware {
function handle(Closure $next) {
try {
// Breakpoint 1
return $next(); // $response
// Breakpoint 2
}
catch (FormException $ex) {
// Breakpoint 3
exit('FormException caught!');
}
}
}
问题是永远不会捕获异常。在管道中的某些地方,应用程序捕捉到异常并打印出一个漂亮的错误页面,但是我的中间件应该捕捉到它,以便它能够正确地处理它
- 断点1应该触发,它确实触发了我想我可以理解为什么您的代码不能捕获异常。请尝试对句柄方法使用以下代码:
上面的代码还没有经过测试,但是当您在返回响应之前查看Laravel文档时,您应该执行代码(在本例中是异常处理逻辑)。有关中间件定义前后的更多信息,请参阅 顺便说一句,也看看这个文件:Laravel/app/Exceptions/Handler.php,我认为它是一个更好的全局处理异常的地方。显然: 是的,这是从L5.2开始的beavhiour。引发异常会导致将响应设置为从异常处理程序返回的响应,然后允许中间件从该点退出 我觉得这很奇怪。可插拔中间件非常适合捕捉异常 有两种方法仍然可以做到这一点:function handle(Closure $next) { try { // Breakpoint 1 $response = $next(); // Breakpoint 2 } catch (FormException $ex) { // Breakpoint 3 exit('FormException caught!'); } return $response; }
- 正确:在
中,这是不够好的,因为包不能触及它App\Exceptions\Handler
- 芬奇::
- 我也有同样的问题。在阅读鲁迪提到的文章时,他们给出了一个可能的解决方案,这对我来说很有效:
public function handle(Request $request, Closure $next) { $response = $next($request); // 'Catch' our FormValidationException and redirect back. if (!empty($response->exception) && $response->exception instanceof FormValidationException) { return redirect()->back()->withErrors($response->exception->form->getErrors())->withInput(); } return $response; }
如何在不接触
文件的情况下捕获错误: 注册您的App\Exceptions\Handler
CustomExceptionHandler
/* @var ExceptionHandler Illuminate\Contracts\Debug\ExceptionHandler */ $previousHandler = null; if (app()->bound(ExceptionHandler::class) === true) { $previousHandler = app()->make(ExceptionHandler::class); } app()->singleton(ExceptionHandler::class, function () use ($previousHandler) { return new CustomExceptionHandler($previousHandler); });
以及您的基本class CustomExceptionHandler implements ExceptionHandlerInterface { /** * @var ExceptionHandlerInterface|null */ private $previous; public function __construct(ExceptionHandlerInterface $previous = null) { $this->previous = $previous; } public function report(Exception $exception) { $this->previous === null ?: $this->previous->report($exception); } public function render($request, Exception $exception) { if ($exception instanceof CustomExceptionHandler) { echo 'This is my particular way to show my errors'; } else { $response = $this->previous === null ? null : $this->previous->render($request, $exception); } return $response; } /** * {@inheritdoc} */ public function renderForConsole($output, Exception $exception) { /* @var OutputInterface $output */ $this->previous === null ?: $this->previous->renderForConsole($output, $exception); } }
CustomExceptionHandler
/* @var ExceptionHandler Illuminate\Contracts\Debug\ExceptionHandler */ $previousHandler = null; if (app()->bound(ExceptionHandler::class) === true) { $previousHandler = app()->make(ExceptionHandler::class); } app()->singleton(ExceptionHandler::class, function () use ($previousHandler) { return new CustomExceptionHandler($previousHandler); });
class CustomExceptionHandler implements ExceptionHandlerInterface { /** * @var ExceptionHandlerInterface|null */ private $previous; public function __construct(ExceptionHandlerInterface $previous = null) { $this->previous = $previous; } public function report(Exception $exception) { $this->previous === null ?: $this->previous->report($exception); } public function render($request, Exception $exception) { if ($exception instanceof CustomExceptionHandler) { echo 'This is my particular way to show my errors'; } else { $response = $this->previous === null ? null : $this->previous->render($request, $exception); } return $response; } /** * {@inheritdoc} */ public function renderForConsole($output, Exception $exception) { /* @var OutputInterface $output */ $this->previous === null ?: $this->previous->renderForConsole($output, $exception); } }
查看源代码,您需要捕获\Exception和\Throwable,以便try-catch在中间件中正常工作。这适用于Laravel 5.8class TryCatchMiddleware { /** * Handle an incoming request. * * @param \Illuminate\Http\Request $request * @param \Closure $next * @return mixed */ public function handle($request, Closure $next) { try { if ( somethingThatCouldThrowAnException() ) { $request->newVariable = true; } } catch (\Exception $e) { // do nothing } catch (\Throwable $e) { // do nothing } return $next($request); } }
不是这样。没有例外会被抓住。它在别的地方被抓住了。我的处理程序中的
对象是显示已处理异常的页面。在哪里以及为什么处理它?在应用程序的处理程序中处理它是可行的,但我需要一个中间件包来完成这项工作。这就是中间件存在的原因,不是吗?在动作前后做些什么。这也是我在Github上得到的。那对我来说太恶心了。例外情况会被捕获,对吗?未从响应对象中提取。。根据您的用例,您可以编辑应用程序的异常处理程序渲染器。@Rudie我完全同意,这是意外行为。但我对我的基本应用程序使用默认的异常处理程序。对于我的api路由组,我希望处理不同的错误,然后这个方法就可以工作了。我同意:中间件中的异常处理在包中很有用:我正在开发一个中间件来处理数据库事务,我需要从中间件提交/回滚。能够捕获异常将非常有用。现在我必须走“时髦”的路;)非常感谢,鲁迪Funky way“拯救了我的一天:)在Laravel v5.5.33上正常工作只有一个包可以做到这一点。如果两个包想要为自己的异常添加异常处理,该怎么办?时髦的$response
方法至少可以做到这一点。每种方法都有它的优点。我不想从$response->exception
中捕获一些可以通过异常()捕获的东西,而是从
捕获。不幸的是,这是中间件堆栈的一部分,有自己的异常捕获。$next
- 正确:在