180 lines
5.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Exceptions;
use App\Helpers\ResponseEnum;
use Illuminate\Auth\AuthenticationException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class Handler extends ExceptionHandler
{
/**
* The list of the inputs that are never flashed to the session on validation exceptions.
*
* @var array<int, string>
*/
protected $dontFlash = [
'current_password',
'password',
'password_confirmation',
];
/**
* Register the exception handling callbacks for the application.
*/
public function register(): void
{
$this->reportable(function (Throwable $e) {
// 记录异常到日志
if ($this->shouldReport($e)) {
LogException::safeLog(
'应用异常: ' . $e->getMessage(),
$e,
[
'file' => $e->getFile(),
'line' => $e->getLine(),
'url' => request()->fullUrl(),
'method' => request()->method(),
'ip' => request()->ip(),
'user_agent' => request()->userAgent(),
]
);
}
});
}
/**
* Render an exception into an HTTP response.
*
* @param Request $request
* @param Throwable $e
* @return Response
*/
public function render($request, Throwable $e): Response
{
// 如果请求期望JSON响应API请求返回JSON格式错误
if ($request->expectsJson() || $request->is('admin/*')) {
return $this->renderJsonException($request, $e);
}
// 非API请求使用默认处理
return parent::render($request, $e);
}
/**
* 渲染JSON格式的异常响应
*
* @param Request $request
* @param Throwable $e
* @return JsonResponse
*/
protected function renderJsonException(Request $request, Throwable $e): JsonResponse
{
// 认证异常
if ($e instanceof AuthenticationException) {
return $this->jsonResponse('授权失败,请先登录', 401, 401);
}
// 参数验证异常
if ($e instanceof ValidationException) {
return $this->jsonResponse('参数错误', 422, 422, $e->errors());
}
// 业务异常
if ($e instanceof BusinessException) {
return $this->jsonResponse($e->getMessage(), $e->getCode());
}
// 其他异常统一处理
return $this->renderSystemException($e);
}
/**
* 渲染系统异常
*
* @param Throwable $e
* @return JsonResponse
*/
protected function renderSystemException(Throwable $e): JsonResponse
{
// 生产环境隐藏详细错误信息
if (!config('app.debug')) {
return $this->jsonResponse('服务器错误', 500, 500);
}
// 开发环境显示详细错误信息
$debugInfo = [
'exception' => get_class($e),
'file' => $e->getFile(),
'line' => $e->getLine(),
'message' => $e->getMessage()
];
return $this->jsonResponse($e->getMessage(), 500, 500, $debugInfo);
}
/**
* 统一的JSON响应格式
*
* @param string $message 错误消息
* @param int $code 错误代码
* @param int $status HTTP状态码
* @param mixed $data 额外数据
* @return JsonResponse
*/
protected function jsonResponse(string $message, int $code, int $status = 200, mixed $data = null): JsonResponse
{
$response = [
'success' => false,
'message' => $message,
'code' => $code,
'data' => $data,
];
// 如果有验证错误添加errors字段
if ($data && is_array($data) && $status === 422) {
$response['errors'] = $data;
$response['data'] = null;
}
return response()->json($response, $status);
}
/**
* 抛出业务异常 - 统一入口
* @param string $message 错误消息
* @param int $code 错误代码 (默认400)
* @throws BusinessException
*/
public static function throw(string $message, int $code = 400): void
{
throw new BusinessException([$code, $message]);
}
/**
* 抛出错误 - throw方法的别名
* @param string $message
* @param int $code
* @throws BusinessException
*/
public static function error(string $message, int $code = 400): void
{
self::throw($message, $code);
}
/**
* 抛出失败异常
* @param string $message
* @throws BusinessException
*/
public static function fail(string $message = '操作失败'): void
{
self::throw($message, 400);
}
}