Laravel 从方法内部处理异常

Laravel 从方法内部处理异常,laravel,exception,laravel-controller,Laravel,Exception,Laravel Controller,我正在使用外部服务(即支付提供商的服务)的API为我的网站实施支付 假设用户单击“购买”,然后我们转到我的控制器,该控制器显示以下内容: public function buyFunction() { $result = $this->ExternalService->pay(); if ($result->success == true) { return 'We are happy'; } } 我还创建了前面提到的externa

我正在使用外部服务(即支付提供商的服务)的API为我的网站实施支付

假设用户单击“购买”,然后我们转到我的控制器,该控制器显示以下内容:

public function buyFunction() {

    $result = $this->ExternalService->pay();

    if ($result->success == true) {
        return 'We are happy';
    }
}
我还创建了前面提到的
externalService
,它具有
pay()
方法:

class ExternalService {

    public function pay() {
        response = //Do stuff with Guzzle to call the API to make the payment

        return response;
    }
}
现在,有时候事情会出错。 假设API返回一个错误——这意味着它抛出了一个GuzzleException——我该如何处理

理想情况下,如果出现错误,我会将其记录下来,并将用户重定向到一个页面,告诉他出了什么问题

我试过的
  • 我曾尝试在pay()函数中使用try/catch语句并使用
    abort(500)
    ,但这不允许我重定向到我想要的页面

  • 我曾尝试在pay()函数中使用try/catch语句并使用
    return redirect('/mypage')
    ,但这只是将重定向对象返回给控制器,然后当它尝试调用
    result->success

  • 我尝试过使用数字2,但也向控制器方法添加了一个try/catch块,但没有任何改变

  • 最后,我找到了两个解决方案。在这两种方法中,我都在pay()方法中使用try/catch块。然后我要么
    返回0
    或我使用
    中止(重定向('/mypage')),则检查控制器

    正确的处理方法是什么?
    如何使用try/catch块?

    根据我的经验,避免处理异常,让它们通过并使用try-catch相应地处理它们。这是最务实的做法。或者,您将在奇怪的地方检查结果是否正确,例如,
    if($result){…}
    。假设一切顺利,除非抛出异常。奖励:口袋妖怪永远不会捕捉到异常$e,除非你特别需要它

    class ExternalService {
    
        public function pay() {
            try {
                response = $client->get(...);
            } catch (BadResponseException $exception) {
                Log::warning('This should not happen check payment api: ' . $exception->getMessage());
                
                throw new PaymentException('Payment did not go through');
            } 
    
            return response;
        }
    }
    
    假设你有自己的例外

    class PaymentException extends HttpException
    {
        public function __construct(?\Exception $previous = null)
        {
            parent::__construct(Response::HTTP_BAD_REQUEST, 'Unexpected error processing the payment', $previous);
        }
    }
    
    这使您能够在控制器中处理流,在控制器中处理重定向是有意义的。有时,如果异常对于web应用程序来说是非常完整或常见的,那么它也可以由异常处理程序来处理

    class PaymentController {
        public function pay(PaymentService $service) {
            try {
                $payment = $service->buyFunction();
            } catch (PaymentException $exception) {
                return redirect()->route('app.payment.error');
            } 
            
            return view('app.payment.success', compact('payment'));
        }
    }
    

    我建议
    pay()
    函数应该捕获Guzzle异常并抛出自己的异常(如果您没有自己的异常类,请不要执行任何操作)。然后在控制器中,您将捕获异常并重定向到错误消息。您的控制器处理诸如中止或重定向之类的最终用户交互,这不是支付处理类的工作。请注意,我建议使用pascal case遵循标准类命名,以便ExternalService而不是ExternalService:)@miken32,这样控制器的每个函数都应该有一个try/catch块?我觉得我必须始终使用try/catch块time@miken32另外,创建我自己的异常类而不是捕获Guzzle的异常有什么好处?这取决于您的用例。您可以在控制器中监视多个异常类,也可以在抛出异常时执行特殊操作。如果您正在编写供第三方使用的代码,抛出您自己的异常会更整洁。谢谢您的回答。我的问题:1)当特定的异常已经存在时,为什么我要创建自己的自定义异常?2) 为什么我不应该捕获一个通用异常-例如:
    catch(\Exception$e)
    ?这样,我可以在try/catch块中包含更多代码。不管我的代码哪一行出错,我都会抓住它。3) 我真的需要在每行中添加一个try/catch块吗?我觉得我必须经常使用它。4) 我的捕手块很大,我的控制器膨胀了。因为你的用户不在乎guzzle,如果你不把它包在一个你更容易处理的东西里就更好了,您可以在各种情况下使用PaymentException,但用户永远不会关心暴食异常,通常认为这是一种良好的做法,在bugsnag sentry等系统中更容易跟踪。暴食异常可以是很多事情。2.因为如果你犯了一个ArrayIndexOutOfBounds错误,它也会处理这个问题,这可能很难调试,如果你是特定的,你不会遇到奇怪的异常。谢谢。顺便说一句,您可以在自定义异常的render方法中处理它,而不是在控制器中使用try/catch块。在我看来,这更简洁,因为你不会用try/catch块使你的控制器膨胀。是的,你可以:)这取决于处理它的位置,我认为控制器通过设计来做一些try-catch是不错的。但是如果错误更一般,则首选Handler.php。