refactor: 重构语言协商中间件,简化语言解析逻辑并增强异常处理,更新相关配置以支持多环境开发
This commit is contained in:
@@ -9,9 +9,21 @@
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
use App\Http\Middleware\EnsureAdminApi;
|
||||
use App\Http\Middleware\EnsurePlayerApi;
|
||||
use App\Http\Middleware\NegotiateLotteryLocale;
|
||||
use App\Lottery\ErrorCode;
|
||||
use App\Support\ApiResponse;
|
||||
use App\Support\LotteryLocale;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Foundation\Application;
|
||||
use Illuminate\Foundation\Configuration\Exceptions;
|
||||
use Illuminate\Foundation\Configuration\Middleware;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
|
||||
|
||||
return Application::configure(basePath: dirname(__DIR__))
|
||||
->withRouting(
|
||||
@@ -24,15 +36,115 @@ return Application::configure(basePath: dirname(__DIR__))
|
||||
->withMiddleware(function (Middleware $middleware): void {
|
||||
// 多语言:必须在其他 api 中间件之前执行,以便鉴权失败时也能按语言返回 msg
|
||||
$middleware->api(prepend: [
|
||||
\App\Http\Middleware\NegotiateLotteryLocale::class,
|
||||
NegotiateLotteryLocale::class,
|
||||
]);
|
||||
$middleware->alias([
|
||||
// 玩家端需登录路由使用;解析 Bearer → Player
|
||||
'lottery.player' => \App\Http\Middleware\EnsurePlayerApi::class,
|
||||
'lottery.player' => EnsurePlayerApi::class,
|
||||
// 后台 API 预留:Sanctum / RBAC
|
||||
'lottery.admin' => \App\Http\Middleware\EnsureAdminApi::class,
|
||||
'lottery.admin' => EnsureAdminApi::class,
|
||||
]);
|
||||
})
|
||||
->withExceptions(function (Exceptions $exceptions): void {
|
||||
//
|
||||
/**
|
||||
* 统一 JSON:与 {@see ApiResponse} 一致,供三端消费;多语言与 {@see LotteryLocale} 对齐。
|
||||
* 覆盖:校验失败、模型/路由 404、限流、未处理异常(生产不泄露堆栈文案)。
|
||||
*/
|
||||
$locale = static function (Request $request): string {
|
||||
return (string) ($request->attributes->get('lottery_locale') ?? LotteryLocale::resolve($request));
|
||||
};
|
||||
|
||||
$exceptions->render(function (ValidationException $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ApiResponse::error(
|
||||
trans('api.validation_failed', [], $locale($request)),
|
||||
ErrorCode::ValidationFailed->value,
|
||||
['errors' => $e->errors()],
|
||||
422,
|
||||
);
|
||||
});
|
||||
|
||||
$exceptions->render(function (ModelNotFoundException $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ApiResponse::error(
|
||||
trans('api.not_found', [], $locale($request)),
|
||||
ErrorCode::NotFound->value,
|
||||
null,
|
||||
404,
|
||||
);
|
||||
});
|
||||
|
||||
$exceptions->render(function (NotFoundHttpException $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ApiResponse::error(
|
||||
trans('api.not_found', [], $locale($request)),
|
||||
ErrorCode::NotFound->value,
|
||||
null,
|
||||
404,
|
||||
);
|
||||
});
|
||||
|
||||
$exceptions->render(function (TooManyRequestsHttpException $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ApiResponse::error(
|
||||
trans('api.too_many_requests', [], $locale($request)),
|
||||
ErrorCode::TooManyRequests->value,
|
||||
null,
|
||||
429,
|
||||
);
|
||||
});
|
||||
|
||||
$exceptions->render(function (HttpException $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
if ($e instanceof NotFoundHttpException || $e instanceof TooManyRequestsHttpException) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$status = $e->getStatusCode();
|
||||
$msg = $e->getMessage();
|
||||
if ($msg === '') {
|
||||
$msg = trans('api.client_error', [], $locale($request));
|
||||
}
|
||||
$code = $status >= 500 ? ErrorCode::InternalError->value : ErrorCode::ClientHttpError->value;
|
||||
|
||||
return ApiResponse::error($msg, $code, null, $status);
|
||||
});
|
||||
|
||||
$exceptions->render(function (Throwable $e, Request $request) use ($locale) {
|
||||
if (! $request->is('api/*')) {
|
||||
return null;
|
||||
}
|
||||
if ($e instanceof ValidationException
|
||||
|| $e instanceof ModelNotFoundException
|
||||
|| $e instanceof NotFoundHttpException
|
||||
|| $e instanceof TooManyRequestsHttpException
|
||||
|| $e instanceof HttpException
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$showDetails = (bool) config('app.debug');
|
||||
$msg = $showDetails ? $e->getMessage() : trans('api.server_error', [], $locale($request));
|
||||
|
||||
return ApiResponse::error(
|
||||
$msg !== '' ? $msg : trans('api.server_error', [], $locale($request)),
|
||||
ErrorCode::InternalError->value,
|
||||
$showDetails ? ['exception' => $e::class] : null,
|
||||
500,
|
||||
);
|
||||
});
|
||||
})->create();
|
||||
|
||||
Reference in New Issue
Block a user