场景描述
比如我们需要对 API 限流抛出的异常进行接管,并重写响应消息,首先应用中间件:
use Dingo\Api\Routing\Router; $api->group([ 'middleware' => 'api.throttle', // 限流中间件 'expires' => 1, // 时间范围,单位“分” 'limit' => 2, // 时间范围内请求次数 ], function (Router $api) {
$api->post('auth/login', 'LoginController@login'); });
讯享网
使用 Postman 进行接口调试,我们会发现在正常请求阶段会多出三个响应头:
讯享网X-RateLimit-Limit # 时间范围内可请求次数 X-RateLimit-Remaining # 时间范围内剩余可请求次数 X-RateLimit-Reset # 到期时间戳
继续重复请求两次后会得到类似如下结果(修改过):
{
"message": "You have exceeded your rate limit.", "result": 0, "status_code": 429 }
异常接管
这里有两种接管方式
- 单一异常接管:
建议在
App\Providers\AppServiceProvider文件中的register()方法内进行编写:讯享网
$this->app->make(Dingo\Api\Exception\Handler::class)->register(function (RateLimitExceededException $e) { return response([ 'message' => '当前请求太过频繁', 'result' => 0, 'status_code' => 429 ])->setStatusCode($e->getStatusCode())->withHeaders($e->getHeaders()); });如果无需使用状态码,可去掉 setStatusCode 方法,仅保留 withHeaders 即可。去掉后 HTTP 状态码响应为 200。 - 多异常接管:
顾名思义,单一异常接管仅适用于单一的服务场景,而 Dingo API 提供了多项服务,如果应用多项时,上述方式就不适用了。
首先,我们在
app/Exceptions目录内创建名为DingoExceptionHandler的类文件,同样我们以限流异常示例,内容如下:讯享网
<?php namespace App\Exceptions; use Dingo\Api\Contract\Debug\ExceptionHandler; use Dingo\Api\Exception\Handler as DingoHandler; use Dingo\Api\Exception\RateLimitExceededException; use Exception; class DingoExceptionHandler extends DingoHandler implements ExceptionHandler { public function handle(Exception $exception) { if ($exception instanceof RateLimitExceededException) { return response([ 'message' => '当前请求太过频繁', 'result' => 0, 'status_code' => 429 ])->withHeaders($exception->getHeaders()); } // TODO: 此处可对其它异常进行同样方式的处理 return parent::handle($exception); } }上方类文件还未应用,此时应当将其注入到框架容器中。
打开
App\Providers\AppServiceProvider文件,在register()方法中添加:$this->app->singleton('api.exception', function () { return new App\Exceptions\DingoExceptionHandler( $this->app['Illuminate\Contracts\Debug\ExceptionHandler'], config('api.errorFormat'), config('api.debug') ); });至此接管完成,再次进行请求测试,响应结果变更为:
讯享网
{ "message": "当前请求太过频繁", "result": 0, "status_code": 429 }响应头中会多出一项
Retry-After,值为剩余可请求时间,单位秒,即 n 秒后允许请求。
说句题外话,之前看到网上很多人在 Lumen 框架中对服务的注册都是通过 $app->register() 写在 bootstrap/app.php 文件内,
个人建议不要这么做,应当统一写在 app\Providers\AppServiceProvider.php 文件内,因为在 app.php 中人家已经注册了这玩意儿
$app->register(App\Providers\AppServiceProvider::class);
那何不规范的写在 Providers 里面呢?例如:
讯享网<?php namespace App\Providers; use App\Exceptions\DingoExceptionHandler; use App\Http\DingoAPI\StrictHeaderAccept; use Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider; use Dingo\Api\Http\Validation\Accept; use Dingo\Api\Provider\LumenServiceProvider as DingoAPI; use Illuminate\Redis\RedisServiceProvider; use Illuminate\Support\ServiceProvider; class AppServiceProvider extends ServiceProvider {
/ * Register any application services. * * @return void */ public function register() {
// Dingo API $this->app->register(DingoAPI::class); // Overwrite request header Accept verify $this->app->singleton(Accept::class, function () {
// Dingo API Accept 严格头的简易白名单方式,StrictHeaderAccept 类参考下方 return new Accept(new StrictHeaderAccept( config('api.standardsTree'), config('api.subtype'), config('api.version'), config('api.defaultFormat')), config('api.strict')); }); // Overwrite rate limit exception render $this->app->singleton('api.exception', function () {
return new DingoExceptionHandler( $this->app['Illuminate\Contracts\Debug\ExceptionHandler'], config('api.errorFormat'), config('api.debug') ); }); // Redis $this->app->register(RedisServiceProvider::class); // IDE Helper if ($this->app->environment() !== 'production') {
$this->app->register(IdeHelperServiceProvider::class); } } }
StrictHeaderAccept.php 内容:
<?php namespace App\Http\DingoAPI; use Dingo\Api\Http\Parser\Accept; use Illuminate\Http\Request; class StrictHeaderAccept extends Accept {
public function parse(Request $request, $strict = false) {
if (in_array($request->getPathInfo(), config('whitelist.request.header'))) {
$strict = false; } return parent::parse($request, $strict); } }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/49043.html