flutter dio^5.3.3实现刷新token

news/2025/2/13 5:14:02/

业务场景:并发请求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的任务,为什么要这样做,举个例子,一群人排长队拉屎,突然没有纸了,这个时候你派谁去拿纸啊?只能找一个没有拉屎的人去给你们排队拉屎的人拿纸去,好了,下面是代码:

import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:hyys_app/api/index.dart';
import 'package:hyys_app/utils/constant.dart';
import 'package:shared_preferences/shared_preferences.dart';class AuthInterceptor extends QueuedInterceptorsWrapper {final Dio tokenDio;final int _statusCode = 401;AuthInterceptor({required this.tokenDio});@overridevoid onRequest(RequestOptions options, RequestInterceptorHandler handler) async {/********************************************携带token请求****************************************************************/SharedPreferences sharedPreferences = await SharedPreferences.getInstance();String? token = sharedPreferences.getString(Constant.tokenKey);options.headers = {'token': token};if (options.method == 'GET') {int timestamp = DateTime.now().millisecondsSinceEpoch;options.queryParameters = {'_t': timestamp, ...options.queryParameters};}/********************************************携带token请求****************************************************************/Response response = await tokenDio.request(options.path);if (response.data['code'] == _statusCode) {debugPrint('${options.path}没有权限,需要刷新token');bool isAuth = await refreshToken();debugPrint('刷新token完成');if (isAuth) {Response response22 = await _retry(options);debugPrint('重试的路径${options.path}');debugPrint('重试的响应${response22.data.toString()}');handler.resolve(response22);}} else {handler.next(options);}}@overridevoid onResponse(Response response, ResponseInterceptorHandler handler) {handler.next(response);}@overridevoid onError(DioException err, ErrorInterceptorHandler handler) {// TODO: implement onErrorsuper.onError(err, handler);}Future<bool> refreshToken() async {debugPrint('刷新token开始');String mpLoginURL = '${Api.baseUrl}/user/mpLogin';Map<String, dynamic> params = {"phoneNumber": '17733405693'};Response response = await tokenDio.request(mpLoginURL, queryParameters: params);if (response.data['code'] == 0) {SharedPreferences sharedPreferences = await SharedPreferences.getInstance();String token = response.data['data']['token'];await sharedPreferences.setString(Constant.tokenKey, token);return true;} else {return false;}}Future<Response<dynamic>> _retry(RequestOptions requestOptions) async {return tokenDio.request<dynamic>(requestOptions.path);}
}

import 'package:dio/dio.dart';
import 'package:hyys_app/utils/constant.dart';
import 'package:shared_preferences/shared_preferences.dart';class TokenInterceptors extends Interceptor {@overridevoid onRequest(RequestOptions options, RequestInterceptorHandler handler) async {/********************************************携带token请求****************************************************************/SharedPreferences sharedPreferences = await SharedPreferences.getInstance();String? token = sharedPreferences.getString(Constant.tokenKey);options.headers = {'token': token};if (options.method == 'GET') {int timestamp = DateTime.now().millisecondsSinceEpoch;options.queryParameters = {'_t': timestamp, ...options.queryParameters};}handler.next(options);/********************************************携带token请求****************************************************************/}
}

import 'dart:convert';import 'package:dio/dio.dart';
import 'package:flutter/foundation.dart';
import 'package:hyys_app/request/auth_interceptor.dart';
import 'package:hyys_app/request/custom_transformer.dart';
import 'package:hyys_app/request/token_interceptors.dart';class DioUtil {// 连接超时时间static const int connectTimeout = 6000;// 响应超时时间static const int receiveTimeout = 6000;static Dio _dio = Dio();Dio get dio => _dio;factory DioUtil() => _getInstance();static DioUtil get instance => _getInstance();static DioUtil? _instance;static DioUtil _getInstance() {_instance ??= DioUtil._internal();return _instance!;}DioUtil._internal() {BaseOptions options = BaseOptions(connectTimeout: const Duration(milliseconds: connectTimeout),receiveTimeout: const Duration(milliseconds: receiveTimeout),responseType: ResponseType.json,);_dio = Dio(options);_dio.transformer = CustomTransformer()..jsonDecodeCallback = parseJson;Dio tokenDio = Dio(options);tokenDio.interceptors.add(TokenInterceptors());_dio.interceptors.add(LogInterceptor(responseBody: false));_dio.interceptors.add(AuthInterceptor(tokenDio: tokenDio));}Map<String, dynamic> _parseAndDecode(String response) {return jsonDecode(response) as Map<String, dynamic>;}Future<Map<String, dynamic>> parseJson(String text) {return compute(_parseAndDecode, text);}Future<Response<T>> request<T>(String url, {Object? data,Map<String, dynamic>? queryParameters,CancelToken? cancelToken,Options? options,ProgressCallback? onSendProgress,ProgressCallback? onReceiveProgress,}) async {Response<T> response = await _dio.request<T>(url,data: data,queryParameters: queryParameters,cancelToken: cancelToken,options: options,onSendProgress: onSendProgress,onReceiveProgress: onReceiveProgress);return response;}
}


http://www.ppmy.cn/news/1196861.html

相关文章

文件夹重命名与大小写转换:提高文件检索准确性的技巧

在文件管理中&#xff0c;文件夹的命名和大小写转换是非常重要的操作。正确的文件夹命名和大小写转换可以提高文件检索的准确性&#xff0c;从而提高工作效率和文件管理的便利性。现在来看云炫文件管理器如何进行文件夹重命名和大小写转换的技巧&#xff0c;以帮助您更好地管理…

概念解析 | 无监督学习 VS Zero-shot学习

注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:无监督学习和Zero-shot学习的关系 无监督学习与Zero-shot学习:本质上的差异还是表面的相似? 背景介绍 无监督学习(Unsupervised Learning)和Zero-shot学习(Zero-shot Learnin…

ardupilot开发 --- 避障方案、SLAM方案探索 篇

0. 无意间发现一张好看的图 1. 无人机避障技术 目前&#xff0c;无人机的避障技术中最为常见的是红外线传感器、超声波传感器、激光传感器以及视觉传感器。那为什么大疆的前视避障首先选择了双目视觉呢&#xff1f; 红外线传感器超声波传感器激光传感器视觉传感器。 参考&am…

了解.NET Framework中自带的泛型委托Predicate和Comparison

Predicate表示定义一组条件并确定指定对象是否符合这些条件的方法。Comparison表示比较同一类型的两个对象的方法。本文主要介绍.NET Framework中自带的泛型委托Predicate和Comparison的使用。 1、Predicate Predicate 相当于 Func和Action类似的委托。表示定义一组条件并确定…

GPT学习笔记

百度的文心一言 阿里的通义千问 通过GPT能力&#xff0c;提升用户体验和产品力 GPT的出现是AI的iPhone时刻。2007年1月9日&#xff0c;第一代iPhone发布&#xff0c;开启移动互联网时代。新一轮的产业革命。 GPT模型发展时间线&#xff1a; Copilot - 副驾驶 应用&#xf…

网络基础扫盲-初识网络

博客内容&#xff1a;初识网络 文章目录 一、OSI七层网络模型二、TCP/IP四层模型1、MAC地址与IP地址 前言 在以前网络不够发之前&#xff0c;各个实验室进行一些研究时需要进行数据的交流&#xff0c;但是那时车马很慢&#xff0c;一生只够跑几次&#xff0c;所以就有人研究了网…

C#将字符串(string)转换为整数(int)几种常见的方法

在C#中&#xff0c;将字符串&#xff08;string&#xff09;转换为整数&#xff08;int&#xff09;有几种常见的方法。以下是一些常用的方法&#xff1a; 使用int.Parse()方法&#xff1a;该方法将字符串转换为整数&#xff0c;并返回相应的整数值。如果字符串无法转换为有效…

AI神助攻,购物更省心:我即将上线一套企业数据高度契合的智能导购APP来开创这一新纪元

将要做什么事的介绍 近期博客写了少了&#xff0c;是因为近小半年来我正在打造一款可私布在企业内部并结合企业自有领域&#xff08;零售商超先行&#xff09;数据的智能导购引擎。截止目前为止还算顺利&#xff0c;并且我将很快将在中国本土的一家生鲜百货超市上线这一款生成…