180 lines
5.0 KiB
PHP
180 lines
5.0 KiB
PHP
<?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);
|
||
}
|
||
}
|