Flutter中DIO拦截器处理401时请求循环问题解决咨询
解决DIO拦截器处理401后请求重复发送的问题
你的问题根源在于拦截器对所有401请求都执行了重试逻辑,包括登录接口本身。当你用错误密码发起登录请求返回401时,拦截器触发refreshToken(用正确密码登录成功),随后会重新发送原来的错误登录请求,导致不必要的重复请求。
具体修复步骤:
1. 修改拦截器,排除登录接口的401重试
在onError拦截逻辑中,判断当前请求路径是否为登录接口(/api/tokens),如果是则直接返回错误,不执行重试:
onError: (DioException e, handler) async { // 仅对非登录接口的401执行token刷新和重试 if (e.response?.statusCode == 401 && e.requestOptions.path != '/api/tokens') { String? newAccessToken = await refreshToken(); if (newAccessToken != null && newAccessToken.isNotEmpty) { // 修正Authorization头格式,添加Bearer前缀 e.requestOptions.headers['Authorization'] = 'Bearer $newAccessToken'; // 重试请求 return handler.resolve(await dio.fetch(e.requestOptions)); } } // 登录接口的401或其他错误,直接返回 return handler.next(e); }
2. 修正请求头中Authorization的格式
原来的onRequest逻辑中,Authorization头缺少Bearer前缀,这可能是导致正常请求触发401的原因之一,需要补上:
onRequest: (options, handler) async { final bearerToken = await _storage.read(key: 'token'); final tenantId = await _storage.read(key: 'tenant'); if (options.path != '/api/tokens') { if (bearerToken != null) { // 正确格式:Bearer + 令牌 options.headers['Authorization'] = 'Bearer $bearerToken'; } options.headers['tenant'] = tenantId; return handler.next(options); } options.headers['tenant'] = tenantId; return handler.next(options); }
3. 完善refreshToken的返回值处理
确保refreshToken在失败时返回null,避免错误信息被当作token使用:
Future<String?> refreshToken() async { final savedUser = await _storage.read(key: 'username'); var credsdata = {"email": savedUser, "password": 'TEMP HARDCODED PASSWORD'}; print('refreshToken() Called'); print('refreshToken() Body: $credsdata'); String baseUrl = await getBaseUrl(); dio.options.baseUrl = baseUrl; try { Response response = await dio.post('/api/tokens', data: credsdata); Map<String, dynamic> data = response.data; var token = data['token']; var refreshToken = data['refreshToken']; await storageService.saveStorageData('token', token); await storageService.saveStorageData('refreshtoken', refreshToken); return token; } on DioException catch (e) { print('刷新token失败: ${e.response?.statusMessage}'); return null; } }
额外提示
实际生产环境中,不要用保存用户名密码的方式刷新token,应该使用后端提供的专用refreshToken接口,用已保存的refreshToken去换取新的accessToken,这是更安全的实现方式。
内容的提问来源于stack exchange,提问作者Ampsyy
相关产品推荐
相关产品推荐

