Preface:
Before, I shared the solution of using Retrofit to refresh token invalidation in Android. Now the Flutter project also has the requirement of "token verification is overdue". So I will briefly summarize how to implement the interceptor function of automatically refreshing token and resending request in the Flutter project, hoping to help you.
Ideas:
1.Dio implements network request
2. Customize the token interceptor to automatically refresh the token and resend the request
3.EventBus sends the login failure event, and the login page pops up
Implementation steps:
1. Configure the gradle dependency of Android directory
dependencies { ... implementation 'de.greenrobot:eventbus:3.0.0-beta1' }
2. Add sdk in pubspec.yaml
dependencies: ... cupertino_icons: ^0.1.0 dio: ^2.1.2 event_bus: ^1.0.0
3. Encapsulate a new access token method
Future<String> getToken() async { String accessToken = DataUtil.getAccessToken; //Get the current accessToken String refreshToken = DataUtil.getRefreshToken; //Get the current refreshToken Dio dio =DioUtil.getInstance().tokenDio; ////Create a new Dio instance dio.options.headers['x-access-token'] = accessToken;//Set the current accessToken try { String url = url; //refreshToken url var response = await dio.get(url,options: options); //Interface requesting refreshToken refresh accessToken = response.data['access_token']; //New accessToken refreshToken = response.data['refresh_token'];//New refreshToken DataUtil.saveRefreshToken(refreshToken); //Save the new refreshToken } on DioError catch (e) { if (e.response == null) { } else { eventBus.fire(new LoginEvent("Login"));//refreshToken expires, eventBus pops up the login page } } return accessToken; }
4. When the token fails, access token is obtained asynchronously
onError(DioError error) async { if (error.response != null && error.response.statusCode == 401) { 401 representative token Be overdue Dio dio = DioUtil().dio;//Get Dio singleton dio.lock(); String accessToken = await getToken(); //Get new accessToken asynchronously DataUtil.saveAccessToken(accessToken); //Save new accessToken dio.unlock(); } super.onError(error); }
5. Restart a request to get data
//Reissue a request to get data 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. Complete code of DIO interceptor
class TokenInterceptor extends Interceptor { @override onError(DioError error) async { if (error.response != null && error.response.statusCode == 401) { //401 for token expiration Dio dio = DioUtil().dio;//Get Dio singleton dio.lock(); String accessToken = await getToken(); //Get new accessToken asynchronously DataUtil.saveAccessToken(accessToken); //Save new accessToken dio.unlock(); //Reissue a request to get data 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<String> getToken() async { String accessToken = DataUtil.getAccessToken; //Get the current accessToken String refreshToken = DataUtil.getRefreshToken; //Get the current refreshToken Dio dio =DioUtil.getInstance().tokenDio; ////Create a new Dio instance dio.options.headers['x-access-token'] = accessToken;//Set the current accessToken try { String url = url; //refreshToken url var response = await dio.get(url,options: options); //Interface requesting refreshToken refresh accessToken = response.data['access_token']; //New accessToken refreshToken = response.data['refresh_token'];//New refreshToken DataUtil.saveRefreshToken(refreshToken); //Save the new refreshToken } on DioError catch (e) { if (e.response == null) { } else { eventBus.fire(new LoginEvent("Login"));//refreshToken expires, eventBus pops up the login page } } return accessToken; } }
7. Add a custom token interceptor
/* *Dio Tool class of network request */ class DioUtil { Dio dio; Dio tokenDio = new Dio(); static DioUtil _instance; static DioUtil getInstance() { if (_instance == null) { _instance = DioUtil(); } return _instance; } //get method Future<Response> get(url, {data, options, cancelToken}) async { String accessToken = DataUtil.getAccessToken; //Get the current accessToken String refreshToken = DataUtil.getRefreshToken; //Get the current refreshToken options = BaseOptions( connectTimeout: 15000, headers: {}, ); dio = new Dio(options); //Add a custom token interceptor 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 sends the login failure event, and the login page pops up
EventBus eventBus = new EventBus(); //eventBus class for custom login class LoginEvent { String text; LoginEvent(this.text); } //Accept eventBus events on the logged in page class LoginPageState extends State<LoginPage> { .... @override void initState() { super.initState(); eventBus.on<LoginEvent>().listen((LoginEvent data) { //TO DO SOMETHING }); } }
9. summary
In the Flutter project, a Dio interceptor that automatically refreshes and resends requests is customized. After constant debugging, the function is finally realized. If you have any questions, please contact me!