Laravel API 响应标准化:提高可读性和可用性

admin 2024-01-03 87 阅读 0评论

在使用 Laravel 构建 API 时,保持一致的响应格式对于清晰度和易用性至关重要。无论是成功响应还是错误响应,以标准化方式呈现数据都可以改善开发人员体验。

在本指南中,我们将探索如何在 Laravel 中使用自定义中间件来实现一致的响应格式。

第 1 步:创建自定义中间件

我们需要创建一个自定义中间件来处理所有 API 响应。我们可以使用 Artisan 命令来创建中间件:

php artisan make:middleware ApiResponseMiddleware

该命令将在 app/Http/Middleware 目录中生成一个名为 ApiResponseMiddleware 的中间件文件。

第 2 步:自定义中间件

我们需要自定义中间件来格式化 API 响应。

打开新创建的中间件文件 ApiResponseMiddleware.php,并更新 handle() 方法如下:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Throwable;

class ApiResponseMiddleware
{
    /**
     * Handle an incoming request.
     *
     * @param Request $request
     * @param Closure(Request): (Response|RedirectResponse) $next
     * @return JsonResponse
     * @throws Throwable
     */
    public function handle(Request $request, Closure $next)
    {
        $response = $next($request);

        // 检查请求是否需要 JSON
        if (!$request->wantsJson() && !$request->is('api/*')) {
            // 强制 API 请求为 JSON 响应
            return $next($request);
        }

        // 设置请求的 Accept 头为 application/json
        $request->headers->set('Accept''application/json');

        // 如果响应是 JsonResponse,则格式化它
        if ($response instanceof JsonResponse) {
            $data = $response->getData(true);

            // 创建标准化响应结构
            $formattedResponse = [
                'success' => array_key_exists('success'$data) ? $data['success'] : $response->status() == 200,
                'statusCode' => array_key_exists('statusCode'$data) ? $data['statusCode'] : $response->status(),
                'statusDescription' => array_key_exists('statusDescription'$data) ? $data['statusDescription'] : ($response->status() == 200 ? 'Successful' : ''),
                'data' => array_key_exists('data'$data) ? $data['data'] : ($response->status() == 200 ? $data : null),
            ];

            // 返回格式化的 JSON 响应
            return response()->json($formattedResponse$response->status());
        }

        // 原样返回响应
        return $next($request);
    }
}

该中间件检查请求是否需要 JSON。如果不需要,则将请求转发到下一个中间件。如果请求需要 JSON,则中间件将设置请求的 Accept 头为 application/json。这将确保响应以正确的格式发送。

然后,中间件检查响应是否是 JsonResponse 的实例。如果是,则中间件将解码响应内容,创建标准化响应结构,并返回格式化的 JSON 响应。对于非 JsonResponse 类型,中间件按原样返回响应。

第3步:注册中间件

我们需要将 ApiResponseMiddleware 注册到 app/Http/Kernel.php 文件中的 $middlewareGroups 数组中。我们可以将其添加到 web 和 api 中间件组中,以便全局应用它:

protected $middlewareGroups = [
    'web' => [
        // 其他中间件...
    ],
    'api' => [
        // 其他中间件...
        \App\Http\Middleware\ApiResponseMiddleware::class,
    ],
];

通过将中间件包含在 api 组中,它将应用于所有 API 路由。

第 4 步:确保控制器响应一致

为了充分利用中间件,请确保您的控制器以一致的格式返回响应。例如,当返回成功的响应时,其结构应如下所示:

return response()->json([
    'success' => true,
    'statusCode' => 200,
    'statusDescription' => 'Successful',
    'data' => $yourData,
]);

第 5 步:(可选)使用 JWT 令牌时防止返回 HTML 页面

为了防止在 JWT 令牌无效时返回 HTML 页面并返回 JSON 响应,您可以自定义 Laravel 的异常处理程序。Laravel 的默认异常处理程序在 App\Exceptions\Handler 类中提供了一个可以重写的 render() 方法。

以下示例说明了如何修改异常处理程序以返回无效 JWT 令牌的 JSON 响应:

1、打开 App\Exceptions\Handler 类。

2、更新 render() 方法如下:

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Throwable;
use Illuminate\Auth\AuthenticationException;


class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Report or log an exception.
     *
     * @param \Throwable $exception
     * @return void
     *
     * @throws \Exception
     */
    public function report(Throwable $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param Request $request
     * @param Throwable $e
     * @return \Symfony\Component\HttpFoundation\Response
     *
     * @throws \Throwable
     */
    public function render($request, Throwable $e)
    {
        // 检查异常是否是 AuthenticationException 的实例(JWT 身份验证)
        if ($e instanceof AuthenticationException) {
            return response()->json([
                'success' => false,
                'statusCode' => 401,
                'statusDescription' => 'Unauthorized: Invalid JWT Token',
                'data' => null,
            ], 401);
        }

        // 您可以根据需要添加多个异常

        if ($request->wantsJson() || $this->isApiRequest($request)) {
            return $this->formatApiResponse($e);
        }

        return parent::render($request$e);
    }


    protected function isApiRequest(Request $request): bool
    {
        // 确保您的 API 以 api 开头,或者您可以根据需要更新
        return Str::startsWith($request->path(), 'api/') || $request->expectsJson();
    }

    protected function formatApiResponse(Throwable $exception): JsonResponse
    {
        return response()->json([
            'success' => false,
            'statusCode' => $this->getStatusCode($exception),
            'statusDescription' => $exception->getMessage(),
            'data' => null,
        ], $this->getStatusCode($exception));
    }

    protected function getStatusCode(Throwable $exception)
    {
        return method_exists($exception'getStatusCode') ? $exception->getStatusCode() : 500;
    }
}

按照上述步骤,您可以在 Laravel 中实现一个自定义中间件,以一致地格式化 API 响应。这种方法可以提高 API 的可读性和可用性,使开发人员更容易使用和理解数据。您可以根据自己的需求调整中间件,以满足特定的 API 要求。例如,您可以添加或删除响应字段,或更改响应结构。

发表评论

快捷回复: 表情:
Addoil Applause Badlaugh Bomb Coffee Fabulous Facepalm Feces Frown Heyha Insidious KeepFighting NoProb PigHead Shocked Sinistersmile Slap Social Sweat Tolaugh Watermelon Witty Wow Yeah Yellowdog
提交
评论列表 (有 0 条评论, 87人围观)