Php Laravel:在哪里抛出HTTP异常 背景
在PHP/Laravel MVC应用程序中,响应代码和主体通常由抛出的异常决定。如果引发HTTP异常(继承自Php Laravel:在哪里抛出HTTP异常 背景,php,laravel,http,exception,coding-style,Php,Laravel,Http,Exception,Coding Style,在PHP/Laravel MVC应用程序中,响应代码和主体通常由抛出的异常决定。如果引发HTTP异常(继承自Symfony\Component\HttpKernel\exception\HttpException),则会引发正确的响应代码(在某些情况下还会引发JSON响应)。还有其他类型的与http无关的异常也可以抛出 问题: 应该在哪里抛出HTTP异常 A仅控制器 B任何地方。应用程序堆栈中的深度或深度 我应该在控制器中捕获我的异常并抛出这些异常的HTTP版本吗?或者,考虑到99%的MVC
Symfony\Component\HttpKernel\exception\HttpException
),则会引发正确的响应代码(在某些情况下还会引发JSON响应)。还有其他类型的与http无关的异常也可以抛出
问题:
应该在哪里抛出HTTP异常
- A仅控制器
- B任何地方。应用程序堆栈中的深度或深度
我应该在控制器中捕获我的异常并抛出这些异常的HTTP版本吗?或者,考虑到99%的MVC框架应用程序都基于HTTP请求>>响应生命周期,我应该在服务类、存储库或实用程序的任何深处抛出HTTP异常吗?应该在哪里抛出HTTP异常 虽然这通常取决于偏好,但框架本身似乎对此采取了固执己见的立场,即您应该将它们扔到任何地方。事实上,Laravel提供了一些有用的帮助,使抛出带有相关响应代码的异常变得更容易:
abort(403, "Exception message"); //Will throw an HTTP exception with code 403
abort_if(true, 400, "Condition failed"); //Will throw a 400 error if the first parameter is true
abort_unless(false, 422, "Condition failed"); //Will throw a 422 error if the first parameter is false
实例:
public function getById($id) {
$model = Model::find($id);
//These are equivalent
if ($model == null) {
abort(404, "$id not found");
}
abort_if($model == null, 404, "$id not found");
abort_unless($model != null, 404, "$id not found");
}
这一点在本手册的第二部分中有所涉及
请注意,abort
确实会引发HTTP异常,因此您仍然可以捕获它们并在需要时处理它们
在这个问题上似乎存在着普遍的误解。我的理解是,问题是应该在哪里抛出HTTP异常,但它正在演变为HTTP上下文中更通用的异常处理
首先,如果您有一个HTTP异常,这意味着只有在HTTP请求/响应周期的上下文中才有意义的异常,那么您应该能够在它发生的地方抛出它,而不是为了在它到达控制器时转换它而抛出其他异常,这就是abort
助手要做的事情
但是,如果您有一个异常(任何类型的异常),在未经处理时应使用特定的http响应代码进行解释,则您可以选择处理该异常:
HttpException
(如果一个完全正常的异常继承自一个在请求/响应生命周期之外没有意义的类,这可能会让人觉得有点奇怪)class Handler {
// ....
public function render($request, $exception) {
if ($exception instanceof SpecialException) {
return response()->view('errors.403', [], 403);
}
return parent::render()
}
}
我的回答并不是针对Laravel,因为我觉得用框架思维工作实际上违背了你最初的问题 始终抛出定制的异常,然后在控制器内处理转换。在本例中,将其包装在一个
HttpException
中。这有几个很好的理由:
- 决定将哪个状态代码和消息委托给实现(在本例中是与框架的集成)。这意味着您可以在任何框架中删除代码并单独处理其错误
- 您决定需要一个CLI命令/worker,现在服务中抛出的
对您的CLI命令没有任何意义HttpException
本质上考虑计算器,它会抛出一个
DivisionByZeroException
。对于控制器,您可以将其包装在HttpException
400错误请求中,然后重新抛出。对于CLI,您的命令可以让异常在屏幕上呈现为除零无论哪种方式,此决定都不是由您的服务部门做出的。我为提及文档提供了一些支持,但就个人而言,使用特定于框架的函数,如中止
与抛出HttpException
是一样的,因此没有明确回答最初的问题。事实上,在我看来,使用框架abort
功能会被认为更糟糕。更多的理由,请看我的答案。@MatthewUsurpabort
的存在与否是问题的答案。之所以有这种方法,是因为Laravel希望鼓励人们在应用程序中的任何地方抛出HTTP异常。如果你不同意这一点,那就不同于说这不是一个有效的答案。我不同意这个答案,因为它似乎只是重复了Laravel实现(Taylor的),并不总是最佳实践或事件是一个好的方法。@AndrewMcLagan我个人认为这是最佳实践。如果您遇到需要抛出HTTP异常的情况,那么您应该能够从任何地方抛出它。在控制器中放置一个try…catch
,只是为了将一个异常转换为另一个异常,这太麻烦了。@apokryfos不。在堆栈中的任何位置抛出HTTP异常都会将该代码与HTTP环境中的使用相耦合。如果您以后想在控制台中使用相同的代码并抛出HTTP异常,该怎么办?回答得很好,理由充分。我同样觉得似乎无法理解为什么,你已经很雄辩地解释了为什么
class Handler {
// ....
public function render($request, $exception) {
if ($exception instanceof SpecialException) {
return response()->view('errors.403', [], 403);
}
return parent::render()
}
}