锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

Flutter 中 Dio 拦截器

时间:2023-07-30 12:07:17 header11连接器

有时我们不需要复杂的应用程序,只需要显示数据列表的简单功能,我们可以通过简单的方法实现:

Future fetchItems() {

return Dio().("https://some-website.com/listing");

}

复制代码

没有错误,也没有必要log打印任何响应信息。

但事实是,几乎没有这么简单的应用程序,有时我们需要从服务器中做更多的响应或调试应用程序,例如:

将动态的Header发送给服务器,如存储SharedPreferences中的值。

检查每个响应头并保存其值。

验证服务器返回的错误,并将其映射到我们的应用程序中可以处理的错误类别中。

此外,我们希望为我们的应用程序无法访问网络时,为我们的应用程序添加简单的缓存功能,以显示该请求的缓存响应;

我们也可以添加它log打印我们的请求和响应信息。

Interceptors拦截器将帮助我们处理这些问题,通过为我们提供错误、请求和响应的具体回调。

在深入之前,我们先来看看如何配置。Dio。

Dio 配置

可以通过BaseOption来配置Dio,这个对象允许我们设置一些初始化的参数Dio实例: connectTimeout,receiveTimeout和baseUrl,它们将用于每一个Api的调用。

Dio createDio() {

return Dio(

BaseOptions(

connectTimeout: 5000,

receiveTimeout: 5000,

baseUrl: "https://some-website.com"

)

);

}

复制代码

但是,拦截器不能添加到基本配置中,我们需要创建它dio在实例中,我们需要在拦截器集合中添加拦截器:

Dio addInterceptors(Dio dio) {

return dio..interceptors.add(InterceptorsWrapper(

onRequest: (RequestOptions options) => requestInterceptor(options),

onResponse: (Response response) => responseInterceptor(response),

onError: (DioError dioError) => errorInterceptor(dioError)));

}

复制代码

我们已经设置了一个dio例子可用于任何一个Api调用。

添加动态Headers

假如我们需要将SharedPreferences存储的一个值作为header我们不能使用传输到服务器的服务器BaseOption中的extra在创建请求时设置静态数据的字段。

InterceptorsWrapper给我们一个RequestOptions对象具有以下属性:

Request dynamic data

Url String path

Query Parameters Map queryParameters

有了这些信息,我们可以实现自己requestInterceptor方法了。

该方法可以返回动态类型:

RequestOptions对象,如果我们想继续要求,

Response如果应用程序想自己处理请求

DioError或dio.reject对象会抛出异常

这将使我们可以灵活的验证每个请求,添加数据以及在必要时抛出错误,我们使用起来只需要添加一些数据,然后处理返回的数据就可以了。

dynamic requestInterceptor(RequestOptions options) async {

SharedPreferences prefs = await SharedPreferences.getInstance();

var token = prefs.get("token");

options.headers.addAll({"Token": "$token${DateTime.now()}"});

return options;

}

复制代码

我们也可以创建它endpoints是否需要添加不同的请求?token的header:

Future getListOfTodos() {

return dio.get("/todos/1", options: Options(headers: {"requiresToken" : true}));

}

复制代码

然后统一处理拦截器:

dynamic requestInterceptor(RequestOptions options) async {

if (options.headers.containsKey("requiresToken")) {

//remove the auxiliary header

options.headers.remove("requiresToken");

SharedPreferences prefs = await SharedPreferences.getInstance();

var header = prefs.get("Header");

options.headers.addAll({"Header": "$header${DateTime.now()}"});

return options;

}

}

复制代码

验证 Response

Response中有Headers,还有Status Code响应数据。我们将响应数据类型设置为动态类型。他可以:

如果我们想继续要求,Response

如果我们在验证数据响应后抛出错误,那就是DioError

如果Header中的isUserActive值为false,然后回到一个DioError.

dynamic responseInterceptor(Response options) async {

if (options.headers.value("verifyToken") != null) {

//if the header is present, then compare it with the Shared Prefs key

SharedPreferences prefs = await SharedPreferences.getInstance();

var verifyToken = prefs.get("VerifyToken");

// if the value is the same as the header, continue with the request

if (options.headers.value("verifyToken") == verifyToken) {

return options;

}

}

return DioError(request: options.request, message: "User is no longer active");

}

复制代码

验证服务器错误

假设服务器有删除用户账户的机制,一旦账户被删除,它将收到错误的信息,因此界面用户界面将跳转到创建用户界面,服务器将返回{"error":"ERROR_001"}我们需要创建一个拦截器来统一处理错误信息。

错误拦截器的类型也是动态的:

如果我们想继续发送错误的请求,我们将返回DioError对象

如果我们想分析请求并返回它Response对象,在这种情况下,应用程序不知道服务器错误,将继续正常要求。

dynamic errorInterceptor(DioError dioError) {

if (dioError.message.contains("ERROR_001")) {

// this will push a new route and remove all the routes that were present

navigatorKey.currentState.pushNamedAndRemoveUntil(

"/login", (Route route) => false);

}

return dioError;

}

复制代码

扩展拦截器

我们可以创建一个拦截器来覆盖它onRequest、onError、onResponse方法。

class AppInterceptors extends Interceptor {

@override

FutureOr onRequest(RequestOptions options) async {

if (options.headers.containsKey("requiresToken")) {

//remove the auxiliary header

options.headers.remove("requiresToken");

SharedPreferences prefs = await SharedPreferences.getInstance();

var header = prefs.get("Header");

options.headers.addAll({"Header": "$header${DateTime.now()}"});

return options;

}

}

@override

FutureOr onError(DioError dioError) {

if (dioError.message.contains("ERROR_001")) {

// this will push a new route and remove all the routes that were present

navigatorKey.currentState.pushNamedAndRemoveUntil(

"/login", (Route route) => false);

}

return dioError;

}

@override

FutureOr onResponse(Response options) async {

if (options.headers.value("verifyToken") != null) {

//if the header is present, then compare it with the Shared Prefs key

SharedPreferences prefs = await SharedPreferences.getInstance();

var verifyToken = prefs.get("VerifyToken");

// if the value is the same as the header, continue with the request

if (options.headers.value("verifyToken") == verifyToken) {

return options;

}

}

return DioError(request: options.request, message: "User is no longer active");

}

}

复制代码

该类可以被轻松的添加到dio对象的拦截器集合中:

Dio addInterceptors(Dio dio) {

dio.interceptors.add(AppInterceptors());

}

复制代码

创建一个简单的缓存

import 'package:dio/dio.dart';

class CacheInterceptor extends Interceptor {

CacheInterceptor();

var _cache = new Map();

@override

onRequest(RequestOptions options) {

return options;

}

@override

onResponse(Response response) {

_cache[response.request.uri] = response;

}

@override

onError(DioError e) {

print('onError: $e');

if (e.type == DioErrorType.CONNECT_TIMEOUT || e.type == DioErrorType.DEFAULT) {

var cachedResponse = _cache[e.request.uri];

if (cachedResponse != null) {

return cachedResponse;

}

}

return e;

}

}

复制代码

之后可以通过添加数据库缓存当方式来改进该缓存拦截器。

记录所有Dio相关的内容

在请求中,我们想通过控制台打印所有的请求信息以及相应信息,以方便我们调试请求中的问题。

和以前一样,我们创建一个新的Interceptor类,实现所有必要的方法,并从请求中记录我们想要的所有信息,此外,我们希望我们的人日志打印的是格式化好的信息:

# REQUEST:

--> GET https://jsonplaceholder.typicode.com/todos/1

...

--> END GET

# RESPONSE:

...

复制代码对于Request,我们希望打印请求参数、请求体、headers、URL

对于Response,我们要打印出URL、Headers、body和状态码

对于错误,我们需要打印状态码和错误本身

class LoggingInterceptors extends Interceptor {

@override

FutureOr onRequest(RequestOptions options) {

print(

"--> ${options.method != null ? options.method.toUpperCase() : 'METHOD'} ${"" + (options.baseUrl ?? "") + (options.path ?? "")}");

print("Headers:");

options.headers.forEach((k, v) => print('$k: $v'));

if (options.queryParameters != null) {

print("queryParameters:");

options.queryParameters.forEach((k, v) => print('$k: $v'));

}

if (options.data != null) {

print("Body: ${options.data}");

}

print(

"--> END ${options.method != null ? options.method.toUpperCase() : 'METHOD'}");

return options;

}

@override

FutureOr onError(DioError dioError) {

print(

"

print(

"${dioError.response != null ? dioError.response.data : 'Unknown Error'}");

print("

}

@override

FutureOr onResponse(Response response) {

print(

"

print("Headers:");

response.headers?.forEach((k, v) => print('$k: $v'));

print("Response: ${response.data}");

print("

}

}

复制代码—> GET https:///jsonplaceholder.typicode.com/todos/1/

Headers:

requiresToken: true

queryParameters:

—> END GET

Headers:

connection: [keep-alive]

set-cookie: [__cfduid=dd3fb888c5f062dd954e06e2e4c1166241567679659; expires=Fri, 04-Sep-20 10:34:19 GMT; path=/; domain=.typicode.com; HttpOnly]

cache-control: [public, max-age=14400]

transfer-encoding: [chunked]

date: [Thu, 05 Sep 2019 10:34:19 GMT]

content-encoding: [gzip]

vary: [Origin, Accept-Encoding]

age: [4045]

cf-cache-status: [HIT]

expect-ct: [max-age=604800, report-uri=“https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct”]

content-type: [application/json; charset=utf-8]

pragma: [no-cache]

server: [cloudflare]

x-powered-by: [Express]

access-control-allow-credentials: [true]

cf-ray: [51178cd29f9b724b-AMS]

etag: [W/“53-hfEnumeNh6YirfjyjaujcOPPT+s”]

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章