Flutter移动端Dio接收超时错误排查:已授权网络权限仍异常
解决Flutter移动端Dio接收超时(第三次请求失败)的问题
结合你描述的场景(网页端正常、移动端前两次请求成功、第三次触发receiveTimeout)和错误日志,咱们来一步步定位和解决问题:
核心问题分析
从日志看,错误是DioErrorType.receiveTimeout: Receiving data timeout[5000ms],且发生在调用ChatGPT SDK的流式接口onCompleteStream时。移动端和网页端的差异、前两次成功第三次失败的现象,大概率和超时配置、网络稳定性、连接资源占用有关。
具体解决方案
1. 调整流式请求的超时时间
ChatGPT的流式响应需要持续接收数据,默认5秒的接收超时显然不够(尤其是第三次请求可能后端处理延迟更高)。你可以给Dio设置更长的接收超时,或者直接针对流式请求取消超时限制:
如果是自定义Dio实例传入ChatGPT SDK:
import 'package:dio/dio.dart'; import 'package:chat_gpt_sdk/chat_gpt_sdk.dart'; // 初始化带超时配置的Dio final dio = Dio(BaseOptions( receiveTimeout: 30000, // 改为30秒,根据实际需求调整 connectTimeout: 5000, )); // 将自定义Dio传入ChatGPT实例 final chatGPT = ChatGPT.instance.builder( "YOUR_API_KEY", dio: dio, );
如果是全局配置Dio:
Dio dio = Dio() ..options.receiveTimeout = const Duration(seconds: 30);
2. 添加请求重试机制
移动端网络波动比网页端大,第三次请求可能刚好遇到弱网。用Dio的重试拦截器自动重试失败的请求:
首先添加dio_retry依赖(pubspec.yaml):
dependencies: dio_retry: ^0.1.2
然后配置拦截器:
import 'package:dio_retry/dio_retry.dart'; dio.interceptors.add(RetryInterceptor( dio: dio, retries: 3, // 最多重试3次 retryDelays: const [1000, 2000, 3000], // 每次重试间隔1、2、3秒 retryEvaluator: (error) => error.type == DioErrorType.receiveTimeout, // 只重试超时错误 ));
3. 优化连接池配置,避免资源占用
后端可能限制了同一客户端的并发连接数,前两次请求占用了连接,第三次请求等待超时。调整Dio的连接池参数:
dio.httpClientAdapter = DefaultHttpClientAdapter() ..onHttpClientCreate = (client) { client.maxConnectionsPerHost = 5; // 增加单host最大连接数 client.connectionTimeout = const Duration(seconds: 5); return client; };
4. 检查流式响应的处理逻辑
确保你在处理流式数据时没有阻塞主线程,且正确关闭stream释放资源:
// 在_sendMessage方法中处理stream void _sendMessage() async { final request = CompleteText( prompt: _textController.text, model: Model.gptTurbo, stream: true, ); final streamSubscription = chatGPT.onCompleteStream(request).listen((response) { if (mounted) { setState(() { // 更新聊天消息UI _messages.add(ChatMessage(text: response.choices[0].text, isUser: false)); }); } }) ..onError((error) { debugPrint("Stream error: ${error.toString()}"); // 这里可以添加错误提示UI }) ..onDone(() { debugPrint("Stream completed"); // stream结束后可以做清理操作 }); // 记得在页面销毁时取消订阅,释放资源 _streamSubscriptions.add(streamSubscription); } // 在dispose方法中取消所有订阅 @override void dispose() { for (var sub in _streamSubscriptions) { sub.cancel(); } super.dispose(); }
5. 移动端特定网络配置检查
虽然前两次请求成功,但还是可以确认以下配置:
- Android:确保
AndroidManifest.xml中添加了必要权限,Android 9+如果用HTTP接口需要开启cleartextTraffic:<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <application android:usesCleartextTraffic="true"> <!-- ... --> </application> - iOS:如果用HTTP接口,在
Info.plist中配置ATS例外:<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <true/> </dict>
优先尝试的步骤
建议先从调整超时时间和添加重试机制入手,这两个是最直接解决超时问题的方案,然后再排查连接资源和处理逻辑的问题。
内容的提问来源于stack exchange,提问作者Abhinav
相关产品推荐
相关产品推荐

