• flutter dio^5.3.3实现刷新token


    业务场景:并发请求A、B、C三个接口,但是这个三个接口都需要携带token才能请求到正确结果,所以我们的正确思维应该是,例如A接口请求到了,但是返回401没有权限,这个时候就需要拦截B和C两个接口不去执行,然后A接口返回401之后我们去请求tokne,拿到token后还有把A接口重试一下,也就是重新请求一次,最后,我们再放行B和C接口的请求。dio^4.0的版本里才有Lock这个类,到了dio^5.0的版本,作者希望使用QueuedInterceptorsWrapper去拦截队列请求。但是一定要注意,整个功能我们需要两个dio的实例,一个 负责正常的业务请求,另一个dio实例负责只请求token的任务,为什么要这样做,举个例子,一群人排长队拉屎,突然没有纸了,这个时候你派谁去拿纸啊?只能找一个没有拉屎的人去给你们排队拉屎的人拿纸去,好了,下面是代码:

    1. import 'package:dio/dio.dart';
    2. import 'package:flutter/cupertino.dart';
    3. import 'package:hyys_app/api/index.dart';
    4. import 'package:hyys_app/utils/constant.dart';
    5. import 'package:shared_preferences/shared_preferences.dart';
    6. class AuthInterceptor extends QueuedInterceptorsWrapper {
    7. final Dio tokenDio;
    8. final int _statusCode = 401;
    9. AuthInterceptor({required this.tokenDio});
    10. @override
    11. void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    12. /********************************************携带token请求****************************************************************/
    13. SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    14. String? token = sharedPreferences.getString(Constant.tokenKey);
    15. options.headers = {'token': token};
    16. if (options.method == 'GET') {
    17. int timestamp = DateTime.now().millisecondsSinceEpoch;
    18. options.queryParameters = {'_t': timestamp, ...options.queryParameters};
    19. }
    20. /********************************************携带token请求****************************************************************/
    21. Response response = await tokenDio.request(options.path);
    22. if (response.data['code'] == _statusCode) {
    23. debugPrint('${options.path}没有权限,需要刷新token');
    24. bool isAuth = await refreshToken();
    25. debugPrint('刷新token完成');
    26. if (isAuth) {
    27. Response response22 = await _retry(options);
    28. debugPrint('重试的路径${options.path}');
    29. debugPrint('重试的响应${response22.data.toString()}');
    30. handler.resolve(response22);
    31. }
    32. } else {
    33. handler.next(options);
    34. }
    35. }
    36. @override
    37. void onResponse(Response response, ResponseInterceptorHandler handler) {
    38. handler.next(response);
    39. }
    40. @override
    41. void onError(DioException err, ErrorInterceptorHandler handler) {
    42. // TODO: implement onError
    43. super.onError(err, handler);
    44. }
    45. Future<bool> refreshToken() async {
    46. debugPrint('刷新token开始');
    47. String mpLoginURL = '${Api.baseUrl}/user/mpLogin';
    48. Map<String, dynamic> params = {"phoneNumber": '17733405693'};
    49. Response response = await tokenDio.request(mpLoginURL, queryParameters: params);
    50. if (response.data['code'] == 0) {
    51. SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    52. String token = response.data['data']['token'];
    53. await sharedPreferences.setString(Constant.tokenKey, token);
    54. return true;
    55. } else {
    56. return false;
    57. }
    58. }
    59. Futuredynamic>> _retry(RequestOptions requestOptions) async {
    60. return tokenDio.request<dynamic>(requestOptions.path);
    61. }
    62. }

    1. import 'package:dio/dio.dart';
    2. import 'package:hyys_app/utils/constant.dart';
    3. import 'package:shared_preferences/shared_preferences.dart';
    4. class TokenInterceptors extends Interceptor {
    5. @override
    6. void onRequest(RequestOptions options, RequestInterceptorHandler handler) async {
    7. /********************************************携带token请求****************************************************************/
    8. SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    9. String? token = sharedPreferences.getString(Constant.tokenKey);
    10. options.headers = {'token': token};
    11. if (options.method == 'GET') {
    12. int timestamp = DateTime.now().millisecondsSinceEpoch;
    13. options.queryParameters = {'_t': timestamp, ...options.queryParameters};
    14. }
    15. handler.next(options);
    16. /********************************************携带token请求****************************************************************/
    17. }
    18. }

    1. import 'dart:convert';
    2. import 'package:dio/dio.dart';
    3. import 'package:flutter/foundation.dart';
    4. import 'package:hyys_app/request/auth_interceptor.dart';
    5. import 'package:hyys_app/request/custom_transformer.dart';
    6. import 'package:hyys_app/request/token_interceptors.dart';
    7. class DioUtil {
    8. // 连接超时时间
    9. static const int connectTimeout = 6000;
    10. // 响应超时时间
    11. static const int receiveTimeout = 6000;
    12. static Dio _dio = Dio();
    13. Dio get dio => _dio;
    14. factory DioUtil() => _getInstance();
    15. static DioUtil get instance => _getInstance();
    16. static DioUtil? _instance;
    17. static DioUtil _getInstance() {
    18. _instance ??= DioUtil._internal();
    19. return _instance!;
    20. }
    21. DioUtil._internal() {
    22. BaseOptions options = BaseOptions(
    23. connectTimeout: const Duration(milliseconds: connectTimeout),
    24. receiveTimeout: const Duration(milliseconds: receiveTimeout),
    25. responseType: ResponseType.json,
    26. );
    27. _dio = Dio(options);
    28. _dio.transformer = CustomTransformer()..jsonDecodeCallback = parseJson;
    29. Dio tokenDio = Dio(options);
    30. tokenDio.interceptors.add(TokenInterceptors());
    31. _dio.interceptors.add(LogInterceptor(responseBody: false));
    32. _dio.interceptors.add(AuthInterceptor(tokenDio: tokenDio));
    33. }
    34. Map<String, dynamic> _parseAndDecode(String response) {
    35. return jsonDecode(response) as Map<String, dynamic>;
    36. }
    37. Future<Map<String, dynamic>> parseJson(String text) {
    38. return compute(_parseAndDecode, text);
    39. }
    40. Future> request(
    41. String url, {
    42. Object? data,
    43. Map<String, dynamic>? queryParameters,
    44. CancelToken? cancelToken,
    45. Options? options,
    46. ProgressCallback? onSendProgress,
    47. ProgressCallback? onReceiveProgress,
    48. }) async {
    49. Response response = await _dio.request(url,
    50. data: data,
    51. queryParameters: queryParameters,
    52. cancelToken: cancelToken,
    53. options: options,
    54. onSendProgress: onSendProgress,
    55. onReceiveProgress: onReceiveProgress);
    56. return response;
    57. }
    58. }

  • 相关阅读:
    Linux入门之关机、挂起和休眠
    橘子学linux03之Linux文件管理(上)
    JAVA设计模式-观察者模式
    Field ‘id‘ doesn‘t have a default value错误解决办法
    【PostgreSQL内核学习(十五)—— (ExecutorRun)】
    14 C++ 二叉树创建 1 头文件 The binary tree creates1 header file
    MediaRecorder实现录音
    c语言遇到的常见问题及解决方案
    apache-atlas-hbase-bridge-源码分析
    OpenWrt下安装Mosquitto
  • 原文地址:https://blog.csdn.net/yusha123/article/details/134187147