【问题标题】:Slim3/DRY - How to handle errors/exceptions correctly without duplicating code?Slim3/DRY - 如何在不重复代码的情况下正确处理错误/异常?
【发布时间】:2016-12-08 13:58:01
【问题描述】:

我正在使用 Slim3 开发一个相当大的 JSON API。我的控制器/动作目前充斥着以下内容:

return $response->withJson([
    'status' => 'error',
    'data' => null,
    'message' => 'Username or password was incorrect'
]);

在应用程序的某些点上,任何事情都可能出错,因此需要做出适当的响应。但常见的一件事是错误响应总是相同的。 status 始终为 errordata 是可选的(在表单验证错误的情况下,data 将包含这些错误),message 设置为向 API 的用户或消费者指示出了什么问题.

我闻到代码重复的味道。如何减少代码重复?

在我的脑海中,我所能想到的就是创建一个自定义异常,比如App\Exceptions\AppException,它采用data 选项,而message 将从$e->getMessage() 获得。

<?php

namespace App\Exceptions;

class AppException extends Exception
{
    private $data;

    public function __construct($message, $data = null, $code = 0, $previous = null)
    {
        $this->data = $data;
        parent::__construct($message, $code, $previous);
    }

    public function getData()
    {
        return $this->data;
    }
}

创建中间件,调用 $next 包裹在 try/catch 中:

$app->add(function($request, $response, $next) {

  try {
    return $next($request, $response);
  }
  catch(\App\Exceptions\AppException $e)
  {
    $container->Logger->addCritical('Application Error: ' . $e->getMessage());
    return $response->withJson([
      'status' => 'error',
      'data' => $e->getData(),
      'message' => $e->getMessage()
    ]);
  }
  catch(\Exception $e)
  {
    $container->Logger->addCritical('Unhandled Exception: ' . $e->getMessage());
    $container->SMSService->send(getenv('ADMIN_MOBILE'), "Shit has hit the fan! Run to your computer and check the error logs. Beep. Boop.");
    return $response->withJson([
      'status' => 'error',
      'data' => null,
      'message' => 'It is not possible to perform this action right now'
    ]);
  }
});

现在我只需在代码中的各个点发送throw new \App\Exceptions\AppException("Username or password incorrect", null)

我唯一的问题是我感觉我使用异常是出于错误的原因,这可能会使调试变得更加困难。

关于减少重复和清理错误响应有什么建议吗?

【问题讨论】:

  • 您正在使用异常,就像在 Slim 中一样。我用 Slim 构建了很多 API,并使用了完全相同的方法——当我想停止请求处理时抛出一个特定的 AppException,我让它被 Slim 的 exceptionHandler 捕获。这是我发现的最干净且必须解耦的方式。只需使用@Mika Tuupola 方法。

标签: php slim slim-3


【解决方案1】:

您可以通过创建输出 JSON 的错误处理程序来获得类似的结果。

namespace Slim\Handlers;

use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;

final class ApiError extends \Slim\Handlers\Error
{
    public function __invoke(Request $request, Response $response, \Exception $exception)
    {
        $status = $exception->getCode() ?: 500;
        $data = [
            "status" => "error",
            "message" => $exception->getMessage(),
        ];
        $body = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
        return $response
                   ->withStatus($status)
                   ->withHeader("Content-type", "application/json")
                   ->write($body);
    }
}

您还必须配置 Slim 以使用您的自定义错误处理程序。

$container = $app->getContainer();

$container["errorHandler"] = function ($container) {
    return new Slim\Handlers\ApiError;
};

检查Slim API Skeleton 的实现示例。

【讨论】:

  • 嘿迈克。我遇到的一个问题是有时用户需要查看错误消息(表单验证、不正确的登录等),但是与数据库问题相关的任何异常,或者由于任何原因没有被捕获的异常我没有想要向用户显示的内容,而不是通用消息。这就是为什么我想将异常分开。这仍然可以这样做吗?我猜这可能是用错误代码来完成的。
  • 您可以执行与您发布的中间件示例相同的操作。当 \App\Exceptions\AppException 显示详细错误时。当其他东西那么详细的错误。
  • @BugHunterUK 你可以使用 Mika 回答就好了,只需使用 if ($exception instanceOf AppException) 检查异常实例是否为 AppException,如果是,则发送异常 JSON,否则,发送通用 '发生错误'JSON。
猜你喜欢
  • 2013-03-21
  • 1970-01-01
  • 2018-07-19
  • 2021-05-03
  • 2011-02-20
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多