Laravel:在哪里抛出HTTP异常

时间:2018-08-08 09:20:59

标签: php laravel http exception coding-style

背景

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

问题

应该在哪里抛出HTTP异常?

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

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

2 个答案:

答案 0 :(得分:5)

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

始终抛出定制的异常,然后在控制器内处理转换。在这种情况下,请将其包装在HttpException中。这样做有几个很好的理由:

  • 决定将哪个状态代码和消息委派给实现(在本例中为与您的框架的集成)。这意味着您可以将代码放入任何框架中,并分别处理其错误。
  • 您决定需要一个CLI命令/工作人员,现在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响应代码来解释,您可以选择以下方式处理:

  1. 使该异常从Symfony HttpException继承(对于一个完全正常的异常,它是从在请求/响应生命周期之外没有意义的类继承的,可能会感到有些奇怪。)
  2. 实施render method within your exception,例如:

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

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