• 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. }

  • 相关阅读:
    智慧园区规划建设解决方案PPT(40页)
    SEO内链作用是什么,seo内链优化怎么做?
    java毕业设计项目源代码javaweb租车汽车租赁汽车出租管理系统
    pycharm配置设置汇总(简单好用)更新中。。。
    Vue电商项目--详情页面--产品售卖属性
    SPI:Java的高可扩展利器
    电子产品设计时如何进行可组装性分析?经典案例分享
    Mac M2/M3 芯片环境配置以及常用软件安装-前端
    数商云SRM采购管理系统应用流程详解,采购平台助力化工行业提升招标采购质效
    【QT】Qt的随身笔记(持续更新...)
  • 原文地址:https://blog.csdn.net/yusha123/article/details/134187147