代码之家  ›  专栏  ›  技术社区  ›  AndrewMcLagan

Laravel:在何处引发HTTP异常

  •  4
  • AndrewMcLagan  · 技术社区  · 6 年前

    背景

    在php/laravel mvc应用程序中,响应代码和主体通常由抛出的异常所指示。如果引发HTTP异常(继承自 Symfony\Component\HttpKernel\Exception\HttpException )会抛出正确的响应代码(在某些情况下还会抛出JSON响应)。还有其他类型的异常与HTTP无关,也可以抛出。

    问题

    在何处引发HTTP异常?

    • 只有控制器
    • 任何地方。应用程序堆栈的深度或深度。

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

    2 回复  |  直到 6 年前
        1
  •  5
  •   Matthew Usurp    6 年前

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

    总是抛出定制的异常 然后在控制器中处理转换。在这种情况下,用一个 HttpException . 有几个很好的理由:

    • 决定将哪个状态代码和消息委托给实现(在本例中是与框架的集成)。这意味着您可以将代码放到任何框架中,并分别处理其错误。
    • 您决定需要一个cli命令/worker,现在 HTTP异常 抛出您的服务对您的cli命令没有意义。

    从本质上来说,考虑计算器,它会 DivisionByZeroException . 对于一个控制器,你可以用一个 HTTP异常 400 BAD REQUEST 重新投掷。对于cli,您的命令可以让异常在屏幕上呈现。 Division By Zero . 无论哪种方式,这一决定都不是由您的服务部门做出的。

        2
  •  0
  •   apokryfos    6 年前

    在何处引发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请求/响应循环的上下文中才有意义的异常,那么您应该能够将它扔到发生它的地方,而不是在它到达控制器时将它转换成其他东西,这就是 中止 帮手们在那里工作。

    但是,如果您有一个异常(任何类型的异常),在未处理时应使用特定的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()
            }
      }