700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Lumen 中对 Dingo API 异常接管并自定义响应结果

Lumen 中对 Dingo API 异常接管并自定义响应结果

时间:2020-12-07 10:00:49

相关推荐

Lumen 中对 Dingo API 异常接管并自定义响应结果

场景描述

比如我们需要对 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的类文件,同样我们以限流异常示例,内容如下:

<?phpnamespace 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里面呢?例如:

<?phpnamespace 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 Helperif ($this->app->environment() !== 'production') {$this->app->register(IdeHelperServiceProvider::class);}}}

StrictHeaderAccept.php内容:

<?phpnamespace 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);}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。