Flutter Android端WebSocket域名解析失败但HTTP连接正常问题
Android端Flutter WebSocket域名解析失败但实际连接可用的解决方案
问题复现
使用package:web_socket_channel实现WebSocket通信、package:http处理HTTP请求时,仅Android端出现以下异常:
SocketException: Failed host lookup: 'my_domain.fun' (OS Error: No address associated with hostname, errno = 7)
核心特征:
- 同设备、同域名下的HTTP请求完全正常
- Web端编译后在移动浏览器中运行无问题
- 异常来自
socket_patch.dart的_NativeSocket.lookup()方法,调用栈无前置代码上下文 - 尝试过预发起HTTP请求缓存域名、调整编译配置,均无法解决
- 已添加
INTERNET和ACCESS_NETWORK_STATE权限,设备网络正常,浏览器可访问目标域名 - 诡异现象:抛出异常后,WebSocket连接实际仍能正常工作
代码示例
当前初始化WebSocket的代码:
class MyClass{ // this is a class property final WebSocketChannel channel = WebSocketChannel.connect(Uri.parse('wss://my_domain.fun')); // constructor connects to listen to the webstream MyClass() { channel.stream.listen((message) { print(message); // more things happen }); } }
解决方案建议
1. 延迟WebSocket初始化时机
类属性初始化阶段处于App启动早期,可能Flutter引擎的网络服务或Android系统DNS还未完全就绪。将WebSocket的创建移到异步方法中执行:
class MyClass { late final WebSocketChannel channel; MyClass() { _initWebSocket(); } Future<void> _initWebSocket() async { try { channel = WebSocketChannel.connect(Uri.parse('wss://my_domain.fun')); channel.stream.listen((message) { print(message); // 后续业务逻辑 }); } catch (e) { print('WebSocket初始化异常: $e'); // 可添加重连逻辑 } } }
2. 手动触发DNS解析后再建立连接
利用HTTP请求能正常解析域名的特性,先通过dart:io手动解析域名,再用IP地址构建WebSocket连接:
import 'dart:io'; class MyClass { late final WebSocketChannel channel; MyClass() { _initWebSocket(); } Future<void> _initWebSocket() async { try { final addresses = await InternetAddress.lookup('my_domain.fun'); if (addresses.isNotEmpty) { final ip = addresses.first.address; // WSS默认端口为443,若你的服务用了其他端口需修改 final uri = Uri.parse('wss://$ip:443'); channel = WebSocketChannel.connect(uri); channel.stream.listen((message) { print(message); }); } } catch (e) { print('DNS解析或WebSocket连接失败: $e'); } } }
3. 配置Android网络安全策略
若目标域名使用自签名证书或非公共CA,需在Android项目中添加网络安全配置:
- 在
res/xml目录下创建network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">my_domain.fun</domain> </domain-config> </network-security-config>
- 在
AndroidManifest.xml的application标签中引用该配置:
<application ... android:networkSecurityConfig="@xml/network_security_config">
4. 捕获并过滤特定异常
既然异常抛出后连接仍能正常工作,可直接捕获该错误并忽略,不影响业务逻辑:
class MyClass{ final WebSocketChannel channel = WebSocketChannel.connect(Uri.parse('wss://my_domain.fun')); MyClass() { channel.stream.listen((message) { print(message); }, onError: (error) { // 仅忽略errno=7的域名解析异常 if (error is SocketException && error.osError?.errorCode == 7) { print("WebSocket域名解析异常已忽略,连接可正常使用"); } else { print("WebSocket异常: $error"); } }); } }
内容的提问来源于stack exchange,提问作者Joshua Haglund
相关产品推荐
相关产品推荐

