Laravel API 响应标准化:提高可读性和可用性
在使用 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 要求。例如,您可以添加或删除响应字段,或更改响应结构。
发表评论