从中间件中的控制器捕获异常

Rud*_*die 6 pipeline middleware exception laravel-5

我有一个可以抛出异常的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(Closure $next) {
    try {
      // Breakpoint 1
      return $next(); // $response
      // Breakpoint 2
    }
    catch (FormException $ex) {
      // Breakpoint 3
      exit('FormException caught!');
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

问题是异常永远不会被捕获.在管道中的Somwhere,应用程序捕获异常并打印一个漂亮的错误页面,但它应该被我的中间件捕获,以便它可以正确处理它.

  • 断点1应该触发,它确实"好"
  • 断点2不应该触发,它不会"好"
  • 断点3应该触发,但它不会"什么??

我可以想象我的中间件没有捕获它的唯一方法是,如果它被捕获到管道内部更深处,而不是进一步向上/周围,但我在其他中间件或管道执行代码中找不到任何try/catch.

这个例外在哪里被捕?为什么?

这可能不是一个很好的模式,但我现在不关心.我比其他任何事都更好奇.我是否完全误解了Laravel的中间件?

我自己的超级简单中间件测试做了我的预期:https://3v4l.org/Udr84 - 捕获并处理中间件内的异常.

笔记:

  • $response物体(返回值$next())为处理异常页面,所以它已经被处理.在哪里以及为何?
  • App\Exceptions\Handler::render()工作中处理异常,但我希望所有逻辑都在中间件包中,而不是在应用程序代码中.

相关的Laravel代码:

  • Kernel::handle() 启动中间件管道<<这有一个catch-all catch(),但我的catch()是第一个,对吗?
  • Pipeline::then() 启动中间件执行
  • Pipeline::getSlice()处理并创建$next闭包

Rud*_*die 14

显然这是设计的:

是的,这是从L5.2开始的beavhiour.抛出异常会导致响应被设置为从异常处理程序返回的响应,然后允许中间件从该点退出.

我觉得这很奇怪.可插拔中间件非常适合捕获异常.

有两种方法可以做到这一点:


Jet*_*tse 6

我有同样的问题。在阅读Rudie 提到的线程时,他们给出了一个对我有用的可能解决方案:

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;
}
Run Code Online (Sandbox Code Playgroud)