前言:

之前分享过在Android中使用Retrofit实现token失效刷新的处理方案,现在Flutter项目也有“token验证过期”的需求,所以接下来我简单总结一下在Flutter项目中如何实现自动刷新token并重发请求的拦截器功能,希望对大家有所帮助。

思路:

1.Dio实现网络请求

2.自定义token拦截器,实现token自动刷新并重发请求

3.EventBus发送登录失效事件,弹出登录页面

实现的步骤:

1.配置Android目录的gradle依赖

dependencies {

...

implementation 'de.greenrobot:eventbus:3.0.0-beta1'

}

2.在pubspec.yaml添加sdk

dependencies:

...

cupertino_icons: ^0.1.0

dio: ^2.1.2

event_bus: ^1.0.0

3.封装一个获取新的accessToken方法

Future getToken() async {

String accessToken = DataUtil.getAccessToken; //获取当前的accessToken

String refreshToken = DataUtil.getRefreshToken; //获取当前的refreshToken

Dio dio =DioUtil.getInstance().tokenDio; ////创建新Dio实例

dio.options.headers['x-access-token'] = accessToken;//设置当前的accessToken

try {

String url = url; //refreshToken url

var response = await dio.get(url,options: options); //请求refreshToken刷新的接口

accessToken = response.data['access_token']; //新的accessToken

refreshToken = response.data['refresh_token'];//新的refreshToken

DataUtil.saveRefreshToken(refreshToken); //保存新的refreshToken

} on DioError catch (e) {

if (e.response == null) {

} else {

eventBus.fire(new LoginEvent("Login"));//refreshToken过期,eventBus弹出登录页面

}

}

return accessToken;

}

4.token失效时,异步获取accessToken

onError(DioError error) async {

if (error.response != null && error.response.statusCode == 401) { 401代表token过期

Dio dio = DioUtil().dio;//获取Dio单例

dio.lock();

String accessToken = await getToken(); //异步获取新的accessToken

DataUtil.saveAccessToken(accessToken); //保存新的accessToken

dio.unlock();

}

super.onError(error);

}

5.重新发起一个请求获取数据

//重新发起一个请求获取数据

var request = error.response.request;

try {

var response = await dio.request(request.path,

data: request.data,

queryParameters: request.queryParameters,

cancelToken: request.cancelToken,

options: request,

onReceiveProgress: request.onReceiveProgress);

return response;

} on DioError catch (e) {

return e;

}

6.Dio拦截器的完整代码

class TokenInterceptor extends Interceptor {

@override

onError(DioError error) async {

if (error.response != null && error.response.statusCode == 401) { //401代表token过期

Dio dio = DioUtil().dio;//获取Dio单例

dio.lock();

String accessToken = await getToken(); //异步获取新的accessToken

DataUtil.saveAccessToken(accessToken); //保存新的accessToken

dio.unlock();

//重新发起一个请求获取数据

var request = error.response.request;

try {

var response = await dio.request(request.path,

data: request.data,

queryParameters: request.queryParameters,

cancelToken: request.cancelToken,

options: request,

onReceiveProgress: request.onReceiveProgress);

return response;

} on DioError catch (e) {

return e;

}

}

super.onError(error);

}

Future getToken() async {

String accessToken = DataUtil.getAccessToken; //获取当前的accessToken

String refreshToken = DataUtil.getRefreshToken; //获取当前的refreshToken

Dio dio =DioUtil.getInstance().tokenDio; ////创建新Dio实例

dio.options.headers['x-access-token'] = accessToken;//设置当前的accessToken

try {

String url = url; //refreshToken url

var response = await dio.get(url,options: options); //请求refreshToken刷新的接口

accessToken = response.data['access_token']; //新的accessToken

refreshToken = response.data['refresh_token'];//新的refreshToken

DataUtil.saveRefreshToken(refreshToken); //保存新的refreshToken

} on DioError catch (e) {

if (e.response == null) {

} else {

eventBus.fire(new LoginEvent("Login"));//refreshToken过期,eventBus弹出登录页面

}

}

return accessToken;

}

}

7.添加自定义的token拦截器

/*

*Dio网络请求的工具类

*/

class DioUtil {

Dio dio;

Dio tokenDio = new Dio();

static DioUtil _instance;

static DioUtil getInstance() {

if (_instance == null) {

_instance = DioUtil();

}

return _instance;

}

//get方法

Future get(url, {data, options, cancelToken}) async {

String accessToken = DataUtil.getAccessToken; //获取当前的accessToken

String refreshToken = DataUtil.getRefreshToken; //获取当前的refreshToken

options = BaseOptions(

connectTimeout: 15000,

headers: {},

);

dio = new Dio(options);

//添加自定义的token拦截器

dio.interceptors.add(new TokenInterceptor());

Response response;

try {

response = await dio.get(url, cancelToken: cancelToken);

} on DioError catch (e) {

print(e.response.data);

}

return response;

}

}

8.EventBus发送登录失效事件,弹出登录页面

EventBus eventBus = new EventBus();

//自定义登录的eventBus类

class LoginEvent {

String text;

LoginEvent(this.text);

}

//在登录的页面接受eventBus事件

class LoginPageState extends State {

....

@override

void initState() {

super.initState();

eventBus.on().listen((LoginEvent data) {

//TO DO SOMETHING

});

}

}

9.总结

在Flutter项目中自定义一个自动刷新并重发请求的Dio拦截器,经过不断调试,最终实现了功能。如果有什么疑问的话,欢迎留言联系我哦!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐