Laravel 从方法内部处理异常
我正在使用外部服务(即支付提供商的服务)的API为我的网站实施支付 假设用户单击“购买”,然后我们转到我的控制器,该控制器显示以下内容: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
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——我该如何处理
理想情况下,如果出现错误,我会将其记录下来,并将用户重定向到一个页面,告诉他出了什么问题
我试过的
abort(500)
,但这不允许我重定向到我想要的页面
return redirect('/mypage')
,但这只是将重定向对象返回给控制器,然后当它尝试调用result->success
返回0如果(结果==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。