业务场景:并发请求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});
-
- @override
- void 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);
- }
- }
-
- @override
- void onResponse(Response response, ResponseInterceptorHandler handler) {
- handler.next(response);
- }
-
- @override
- void onError(DioException err, ErrorInterceptorHandler handler) {
- // TODO: implement onError
- super.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
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 {
- @override
- void 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
> request( - String url, {
- Object? data,
- Map<String, dynamic>? queryParameters,
- CancelToken? cancelToken,
- Options? options,
- ProgressCallback? onSendProgress,
- ProgressCallback? onReceiveProgress,
- }) async {
- Response
response = await _dio.request(url, - data: data,
- queryParameters: queryParameters,
- cancelToken: cancelToken,
- options: options,
- onSendProgress: onSendProgress,
- onReceiveProgress: onReceiveProgress);
-
- return response;
- }
- }