Flutter中Dio调用API时200正常但403请求崩溃,求错误处理方案
问题根源
Dio 默认会把非2xx范围的HTTP状态码(比如403)当作异常抛出,所以你的403响应根本不会走到if(response.statusCode == 403)的判断逻辑里,而是直接进入on DioException catch (e)块。另外你每次调用接口都重复添加CookieManager拦截器,这会导致拦截器重复注册,可能引发额外的崩溃问题。
修复步骤
1. 全局配置Dio拦截器(避免重复添加)
把CookieManager拦截器的初始化放到Dio实例的全局配置里,不要每次调用接口都添加。比如在你的网络初始化类里:
// 全局初始化Dio和CookieJar final cookieJar = CookieJar(); final dio = Dio() ..interceptors.add(CookieManager(cookieJar));
2. 处理403状态码(两种可选方法)
方法一:让Dio允许403状态码不抛出异常
在请求的Options里设置validateStatus,指定哪些状态码视为有效响应:
final response = await dio.post( '$baseUrl/durian/scan-durian', options: Options( headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $accessToken', }, // 允许200和403都视为有效响应,不抛出异常 validateStatus: (status) => status == 200 || status == 403, ), data: { 'durian_tag': durianTag, 'durian_grade': durianGrade, }, );
这样403响应会进入后续的if判断,你的原有状态码处理逻辑就能正常执行。
方法二:在DioException中捕获并处理403
如果不想修改validateStatus,可以在异常块里解析响应:
} on DioException catch (e) { print('Dio异常: ${e.message}'); // 检查是否有响应且状态码是403 if (e.response != null && e.response!.statusCode == 403) { print('403状态码捕获'); return {'success': true, 'message': 'pass'}; } // 处理其他Dio异常 return {'success': false, 'message': '请求异常: ${e.message}'}; } catch (e) { print('其他异常: $e'); return {'success': false, 'message': '未知错误'}; }
完整修改后的代码示例
推荐结合全局Dio配置+方法一的实现:
// 全局Dio配置(放在单独的网络管理类或全局初始化处) final cookieJar = CookieJar(); final dio = Dio() ..interceptors.add(CookieManager(cookieJar)); Future<dynamic> scanDurian(String durianTag, String durianGrade) async { // Retrieve tokens from SharedPreferences final accessToken = await AuthService.getAccessToken(); final refreshToken = await AuthService.getRefreshToken(); // Save cookies to the cookie jar List<Cookie> cookies = [ Cookie('accessToken', accessToken!), Cookie('refreshToken', refreshToken!), ]; cookieJar.saveFromResponse(Uri.parse(baseUrl), cookies); try { final response = await dio.post( '$baseUrl/durian/scan-durian', options: Options( headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer $accessToken', }, // 允许200和403作为有效响应 validateStatus: (status) => status == 200 || status == 403, ), data: { 'durian_tag': durianTag, 'durian_grade': durianGrade, }, ); if (response.statusCode == 200) { print(response.statusCode); final responseData = response.data; return {'success': true, 'data': responseData}; } else if (response.statusCode == 403) { print(response.statusCode); return {'success': true, 'message': 'pass'}; } else { print(response.statusCode); return {'success': false, 'message': 'Failed to scan durian'}; } } on DioException catch (e) { print('Dio请求异常: $e'); return {'success': false, 'message': '请求失败: ${e.message}'}; } catch (e) { print('未知异常: ${e.toString()}'); return {'success': false, 'message': '未知错误'}; } }
额外说明
- 重复添加拦截器会导致Dio实例的拦截器链越来越长,可能引发请求重复处理、内存泄漏或逻辑混乱,所以一定要全局初始化一次。
- 物理设备和NGROK的使用不影响这个问题的修复,核心是Dio的异常处理规则。
内容的提问来源于stack exchange,提问作者dante0422
相关产品推荐
相关产品推荐

