laravel-response
laravel-response copied to clipboard
配置API限流,请求超过限制后, 响应方式为视图
laravel version: 10.28.0
大致配置:
config/response.php
....
'exception' => [
\Illuminate\Validation\ValidationException::class => [
'code' => 422,
],
\Illuminate\Auth\AuthenticationException::class => [
],
\Symfony\Component\HttpKernel\Exception\NotFoundHttpException::class =>[
'message' => '',
],
\Illuminate\Database\Eloquent\ModelNotFoundException::class => [
'message' => '',
],
// 在这里新增了一个API限流异常
\Illuminate\Http\Exceptions\ThrottleRequestsException::class => [
'code' => 429,
'message' => 'Too Many Requests'
],
],
....
加了一个 Accept App\Http\Middleware\AcceptHeader.php
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class AcceptHeader
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
$request->headers->set('Accept', 'application/json');
$request->headers->set('Content-Type', 'application/json');
return $next($request);
}
}
App\Http\Kernel.php
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
\Illuminate\Routing\Middleware\ThrottleRequests::class.':api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
\App\Http\Middleware\AcceptHeader::class
//\App\Http\Middleware\ListenerHttpRequest::class
],
];
然后看源码 怀疑还是 Accept没有生效?没办法,目前在App\Exceptions\Handle.php增加了一个 render方法
public function render($request, Throwable $exception)
{
// if ($exception instanceof ThrottleRequestsException) {
// return Response::fail($exception->getMessage(), 429);
// }
return $this->prepareJsonResponse($request, $exception);
}
但是目前这样子的话。在访问API超过限制(1分钟5次请求) 后, 直接以浏览器方式请求的话 显示如下:
如果是用API工具发起请求。 会出现请求阻塞。一直到超过限流时间的同时获取到数据.....
现在好想找到原因了, 不需要 render ....
将 \App\Http\Middleware\AcceptHeader::class 从 $middlewareGroups.api 的位置移动到 $middleware 这里就可以了...
这是什么原因呢?
出现问题的原因可能是部分路由请求不符合 $request->expectsJson():
// vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php
protected function renderExceptionResponse($request, Throwable $e)
{
return $this->shouldReturnJson($request, $e)
? $this->prepareJsonResponse($request, $e)
: $this->prepareResponse($request, $e);
}
// vendor/laravel/framework/src/Illuminate/Http/Concerns/InteractsWithContentTypes.php
public function expectsJson()
{
return ($this->ajax() && ! $this->pjax() && $this->acceptsAnyContentType()) || $this->wantsJson();
}
放AcceptHeader 到$middleware中,相当于让所有路由请求都成了 api 请求,可以按这思路检查下