本文目录导读:

在Laravel中统一处理API异常响应格式,我推荐以下几种方案:
基础方案:自定义异常处理器
1 创建统一响应格式
// app/Exceptions/ApiResponseTrait.php
<?php
namespace App\Exceptions;
use Illuminate\Http\JsonResponse;
trait ApiResponseTrait
{
/**
* 成功响应
*/
protected function success($data = null, string $message = '操作成功', int $code = 200): JsonResponse
{
return response()->json([
'code' => $code,
'message' => $message,
'data' => $data,
'timestamp' => now()->timestamp
]);
}
/**
* 失败响应
*/
protected function error(string $message = '操作失败', int $code = 400, $data = null): JsonResponse
{
return response()->json([
'code' => $code,
'message' => $message,
'data' => $data,
'timestamp' => now()->timestamp
]);
}
/**
* 分页响应
*/
protected function paginated($paginator, string $message = '操作成功'): JsonResponse
{
return response()->json([
'code' => 200,
'message' => $message,
'data' => [
'items' => $paginator->items(),
'pagination' => [
'current_page' => $paginator->currentPage(),
'per_page' => $paginator->perPage(),
'total' => $paginator->total(),
'last_page' => $paginator->lastPage(),
'has_more_pages' => $paginator->hasMorePages()
]
]
]);
}
}
2 自定义异常类
// app/Exceptions/ApiException.php
<?php
namespace App\Exceptions;
use Exception;
use Throwable;
class ApiException extends Exception
{
protected $data;
public function __construct(
string $message = 'API错误',
int $code = 400,
$data = null,
Throwable $previous = null
) {
parent::__construct($message, $code, $previous);
$this->data = $data;
}
public function getData()
{
return $this->data;
}
}
// 自定义业务异常
class BusinessException extends ApiException
{
public function __construct(string $message = '业务处理失败', $data = null)
{
parent::__construct($message, 422, $data);
}
}
// 权限异常
class PermissionException extends ApiException
{
public function __construct(string $message = '没有权限执行此操作', $data = null)
{
parent::__construct($message, 403, $data);
}
}
3 修改异常处理器
// app/Exceptions/Handler.php
<?php
namespace App\Exceptions;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Throwable;
class Handler extends ExceptionHandler
{
use ApiResponseTrait;
protected $dontReport = [
ApiException::class,
ValidationException::class,
];
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
public function register(): void
{
$this->reportable(function (Throwable $e) {
// 日志记录
if (config('app.debug')) {
\Log::error($e->getMessage(), [
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
});
$this->renderable(function (Throwable $e, $request) {
// 只处理API请求
if ($request->is('api/*') || $request->expectsJson()) {
return $this->handleApiException($e, $request);
}
});
}
/**
* 处理API异常
*/
protected function handleApiException(Throwable $e, $request): JsonResponse
{
// 自定义业务异常
if ($e instanceof ApiException) {
return $this->error($e->getMessage(), $e->getCode(), $e->getData());
}
// 验证异常
if ($e instanceof ValidationException) {
return $this->error(
'数据验证失败',
422,
['errors' => $e->errors()]
);
}
// 认证异常
if ($e instanceof AuthenticationException) {
return $this->error('未认证或认证已过期', 401);
}
// 授权异常
if ($e instanceof AuthorizationException) {
return $this->error('没有权限执行此操作', 403);
}
// 模型未找到
if ($e instanceof ModelNotFoundException) {
return $this->error('资源不存在', 404);
}
// 路由未找到
if ($e instanceof NotFoundHttpException) {
return $this->error('请求路径不存在', 404);
}
// 请求方法不允许
if ($e instanceof MethodNotAllowedHttpException) {
return $this->error('请求方法不允许', 405);
}
// 数据库查询异常
if ($e instanceof QueryException) {
return $this->error('数据库操作失败', 500);
}
// 其他异常
if (config('app.debug')) {
return $this->error($e->getMessage(), 500, [
'debug' => [
'exception' => get_class($e),
'trace' => $e->getTrace(),
]
]);
}
// 生产环境默认响应
return $this->error('服务器内部错误', 500);
}
}
使用中间件方案
// app/Http/Middleware/ForceJsonResponse.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class ForceJsonResponse
{
public function handle(Request $request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
$response = $next($request);
// 确保所有API响应都是JSON格式
if (!$response instanceof \Illuminate\Http\JsonResponse) {
$response = response()->json([
'code' => $response->getStatusCode(),
'message' => $response->getContent(),
'data' => null
], $response->getStatusCode());
}
return $response;
}
}
高级方案:统一异常响应服务
// app/Services/ApiResponseService.php
<?php
namespace App\Services;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\MessageBag;
class ApiResponseService
{
/**
* 成功响应
*/
public function success($data = null, string $message = '操作成功'): JsonResponse
{
return $this->sendResponse($data, $message, 200, true);
}
/**
* 创建成功
*/
public function created($data = null, string $message = '创建成功'): JsonResponse
{
return $this->sendResponse($data, $message, 201, true);
}
/**
* 无内容
*/
public function noContent(string $message = '操作成功'): JsonResponse
{
return $this->sendResponse(null, $message, 204, true);
}
/**
* 错误响应
*/
public function error(string $message, int $code = 400, $errors = null): JsonResponse
{
return $this->sendResponse(null, $message, $code, false, $errors);
}
/**
* 验证错误
*/
public function validationError(MessageBag $errors): JsonResponse
{
return $this->error('数据验证失败', 422, [
'errors' => $errors->toArray()
]);
}
/**
* 发送响应
*/
protected function sendResponse($data, string $message, int $code, bool $status, $errors = null): JsonResponse
{
$response = [
'code' => $code,
'status' => $status,
'message' => $message,
'data' => $data,
'timestamp' => now()->toISOString(),
'time' => round(microtime(true) - LARAVEL_START, 3),
];
if ($errors) {
$response['errors'] = $errors;
}
return response()->json($response, $code);
}
/**
* 分页响应
*/
public function paginator($items, int $total, int $page, int $perPage): JsonResponse
{
return $this->success([
'items' => $items,
'meta' => [
'total' => $total,
'page' => $page,
'per_page' => $perPage,
'last_page' => ceil($total / $perPage),
],
]);
}
}
在控制器中使用
// app/Http/Controllers/Api/UserController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\ApiResponseService;
use Illuminate\Http\Request;
class UserController extends Controller
{
protected $apiResponse;
public function __construct(ApiResponseService $apiResponse)
{
$this->apiResponse = $apiResponse;
}
public function index()
{
try {
$users = User::paginate(15);
return $this->apiResponse->paginator(
$users->items(),
$users->total(),
$users->currentPage(),
$users->perPage()
);
} catch (\Exception $e) {
return $this->apiResponse->error('获取用户列表失败: '.$e->getMessage());
}
}
public function store(Request $request)
{
try {
$validated = $request->validate([
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users',
]);
$user = User::create($validated);
return $this->apiResponse->created($user);
} catch (ValidationException $e) {
return $this->apiResponse->validationError($e->errors());
} catch (\Exception $e) {
return $this->apiResponse->error('创建用户失败');
}
}
}
使用服务提供者
// app/Providers/ApiResponseServiceProvider.php
<?php
namespace App\Providers;
use App\Services\ApiResponseService;
use Illuminate\Support\ServiceProvider;
class ApiResponseServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('api.response', function ($app) {
return new ApiResponseService();
});
}
public function boot()
{
//
}
}
全局助手函数
// app/helpers.php
<?php
if (!function_exists('api_success')) {
function api_success($data = null, string $message = '操作成功')
{
return app('api.response')->success($data, $message);
}
}
if (!function_exists('api_error')) {
function api_error(string $message, int $code = 400, $errors = null)
{
return app('api.response')->error($message, $code, $errors);
}
}
配置异常级别
// config/api.php
<?php
return [
// 是否显示调试信息
'debug' => env('API_DEBUG', false),
// 响应格式配置
'response' => [
'include_timestamp' => true,
'include_time_cost' => true,
'snake_case' => false,
],
// 错误码配置
'error_codes' => [
'success' => 200,
'created' => 201,
'bad_request' => 400,
'unauthorized' => 401,
'forbidden' => 403,
'not_found' => 404,
'validation_error' => 422,
'server_error' => 500,
],
];
异常响应示例
// 成功响应
{
"code": 200,
"status": true,
"message": "操作成功",
"data": {
"id": 1,
"name": "Test User"
},
"timestamp": "2024-01-15T10:30:00+00:00",
"time": 12.3
}
// 验证错误响应
{
"code": 422,
"status": false,
"message": "数据验证失败",
"data": null,
"timestamp": "2024-01-15T10:30:00+00:00",
"time": 5.6,
"errors": {
"email": ["The email field is required."],
"name": ["The name field is required."]
}
}
// 服务器错误响应
{
"code": 500,
"status": false,
"message": "服务器内部错误",
"data": null,
"timestamp": "2024-01-15T10:30:00+00:00",
"time": 8.9
}
推荐方案
建议采用方案1(自定义异常处理器)+ 方案4(服务类)的组合:
- 使用
ApiException和业务异常类处理业务异常 - 使用
ApiResponseService统一响应格式 - 在
Handler中统一处理所有异常 - 在控制器中使用
try-catch或直接抛出异常
这样既保证了异常处理的统一性,又提供了灵活性,如果是团队项目,建议将响应格式做成可配置的,方便不同场景适配。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播