Laravel:在哪里抛出HTTP异常

And*_*gan 7 php coding-style exception http laravel

背景

在PHP / Laravel MVC应用程序中,响应代码和主体通常由抛出的Exception决定。如果抛出了HTTP异常(继承自Symfony\Component\HttpKernel\Exception\HttpException),则抛出正确的响应代码(在某些情况下为JSON响应)。还有其他与HTTP不相关的异常类型也可以引发。

HTTP异常应该在哪里抛出?

  • A仅控制器
  • B任何地方。应用程序堆栈中的深度或深度。

我是否应该在控制器中捕获异常并抛出这些异常的HTTP版本?还是考虑到99%的MVC框架应用程序都基于HTTP请求>>响应生命周期,我是否应该在服务类,存储库或实用程序中的任何地方抛出HTTP异常?

小智 7

我的答案不是针对Laravel,因为我觉得使用框架思维方式实际上与您的最初问题背道而驰。

始终抛出定制的异常,然后在控制器内处理转换。在这种情况下,将其包装在中HttpException。原因有很多:

  • 决定将哪个状态代码和消息委派给实现(在这种情况下,是与框架的集成)。这意味着您可以将代码放在任何框架中并分别处理其错误。
  • 您决定需要一个CLI命令/工作人员,而现在您HttpException对服务的投入对CLI命令毫无意义。

本质上考虑一个计算器,它将抛出一个DivisionByZeroException。对于控制器,您可以将其包装HttpException 400 BAD REQUEST并重新抛出。对于CLI,您的命令可以只让异常在屏幕上呈现Division By Zero无论哪种方式,您的服务都不会做出此决定。

  • 很好的回答和充分的理由。我感到似乎无法理解为什么,您已经雄辩地解释了为什么 (2认同)

apo*_*fos 5

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

实际例子:

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

这在手册的错误处理部分有所涉及

请注意,这abort确实会引发 HTTP 异常,因此您仍然可以在需要时捕获它们并处理它们。

关于这个问题似乎存在普遍的误解。我的理解是,问题是应该在哪里抛出 HTTP 异常,但它正在演变为 HTTP 上下文中更通用的异常处理。

首先,如果您有一个 HTTP 异常,这意味着该异常仅在 HTTP 请求/响应周期的上下文中有意义,那么您应该能够将它抛出它发生的地方,而不是抛出其他用于转换的东西当它到达控制器时,这就是abort助手要做的事情。

但是,如果您有一个异常(任何类型的异常),在未处理时应使用特定的 http 响应代码进行解释,您可以选择处理:

  1. 使该异常从 Symfony 继承HttpException(这可能感觉有点奇怪,一个完全正常的异常继承自一个在请求/响应生命周期之外没有意义的类)。
  2. render在您的异常中实现该方法,例如:

    class SpecialException extends Exception { 
       public function render() {
            return response()->view('errors.403', [], 403);
       }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  3. 在您的 \App\Exceptions\Handler 中具有特定的处理行为,例如:

    class Handler {
           // ....
          public function render($request, $exception) {
              if ($exception instanceof SpecialException) {
                  return response()->view('errors.403', [], 403);
              }
              return parent::render()
          }
    }
    
    Run Code Online (Sandbox Code Playgroud)