在PHP / Laravel MVC应用程序中,响应代码和主体通常由抛出的异常决定。如果抛出HTTP异常(从Symfony\Component\HttpKernel\Exception\HttpException
继承),则抛出正确的响应代码(在某些情况下为JSON响应)。还有其他与HTTP不相关的异常类型也可以抛出。
应该在哪里抛出HTTP异常?
我应该在控制器中捕获我的异常并抛出这些异常的HTTP版本吗?还是考虑到99%的MVC框架应用程序都基于HTTP请求>>响应生命周期,我是否应该在服务类,存储库或实用程序中的任何地方抛出HTTP异常?
答案 0 :(得分:5)
我的回答不是针对Laravel,因为我觉得使用框架思维方式实际上与您的最初问题背道而驰。
始终抛出定制的异常,然后在控制器内处理转换。在这种情况下,请将其包装在HttpException
中。这样做有几个很好的理由:
HttpException
引发的服务对您的CLI命令毫无意义。本质上考虑一个计算器,它将抛出一个DivisionByZeroException
。对于控制器,您可以将其包装在HttpException
400 BAD REQUEST
中并重新抛出。对于CLI,您的命令可以只让异常在屏幕Division By Zero
上呈现。 无论哪种方式,您的服务都不会做出此决定。
答案 1 :(得分:0)
应该在哪里抛出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");
}
这在手册的Error handling section中已涉及
请注意,abort
确实会引发HTTP异常,因此您仍然可以捕获它们并在需要时对其进行处理。
对于这个问题似乎有一个普遍的误解。据我了解,问题在于应该在哪里引发HTTP异常,但是它正在演变为在HTTP上下文中更通用的异常处理。
首先,如果您有HTTP异常,这意味着仅在HTTP请求/响应周期的上下文中有意义的异常,那么您应该能够将其扔在发生的地方,而不会在abort
帮助者要做的是在到达控制器时对其进行转换的目的。
但是,如果您有一个异常(任何形式的异常),当不处理它们时应使用特定的http响应代码来解释,您可以选择以下方式处理:
HttpException
继承(对于一个完全正常的异常,它是从在请求/响应生命周期之外没有意义的类继承的,可能会感到有些奇怪。)实施render
method within your exception,例如:
class SpecialException extends Exception {
public function render() {
return response()->view('errors.403', [], 403);
}
}
例如,在\ App \ Exceptions \ Handler中具有特定的处理行为:
class Handler {
// ....
public function render($request, $exception) {
if ($exception instanceof SpecialException) {
return response()->view('errors.403', [], 403);
}
return parent::render()
}
}