Flutter Web端InternetAddress.lookup报Unsupported operation错误解决
报错根因
dart:io 提供的 InternetAddress.lookup 是基于原生系统套接字实现的DNS查询能力,Web端运行在浏览器安全沙箱中,没有底层套接字操作权限,也不支持直接发起自定义DNS查询。不管是直接引用dart:io还是使用universal_io做兼容层,都没法绕过浏览器的这个限制,所以必然抛出不支持操作的错误。
适配方案
核心思路是按运行平台拆分检测逻辑,保留原有移动端/桌面端的可靠检测逻辑,Web端单独使用浏览器支持的HTTP探测方式实现连通性判断,对外统一输出状态流,上层业务无需感知平台差异。
- 引入
foundation库的kIsWeb常量做平台分支判断,不要在Web环境下调用任何dart:io相关的网络API - Web端放弃DNS探测方案,改用带超时的HEAD请求做连通性校验,优先使用自有业务服务的健康检查接口,避免第三方公共地址的跨域拦截问题
- 保留原有
connectivity_plus的网络状态变化监听逻辑,在网络切换事件触发时重新执行连通性校验,和原有移动端行为对齐 - 可直接引入官方维护的跨平台
http库实现探测请求,无需单独处理Web端原生API的条件导入问题,兼容全平台编译
修正后完整实现代码
首先在pubspec.yaml中添加依赖:
dependencies: http: ^1.1.0 # 跨平台HTTP请求库,适配Web/移动端/桌面端 connectivity_plus: ^5.0.0 rxdart: ^0.27.7
服务层实现代码:
import 'dart:async'; import 'dart:io' show SocketException, InternetAddress; import 'package:flutter/foundation.dart'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:rxdart/rxdart.dart'; import 'package:http/http.dart' as http; enum ConnectionStatus { online, offline, } class CheckInternetConnection { final Connectivity _connectivity = Connectivity(); // 替换为自有业务域名,避免第三方地址跨域拦截 static const String _probeAddress = 'www.your-business-domain.com'; static const Duration _probeTimeout = Duration(seconds: 3); /// 初始状态默认设为在线 final _controller = BehaviorSubject.seeded(ConnectionStatus.online); StreamSubscription? _connectionSubscription; CheckInternetConnection() { _checkInternetConnection(); } Stream<ConnectionStatus> internetStatus() { _connectionSubscription ??= _connectivity.onConnectivityChanged .listen((_) => _checkInternetConnection()); return _controller.stream; } Future<void> _checkInternetConnection() async { try { // 网络切换后短暂等待,避免网卡刚启动时网络未就绪导致误判 await Future.delayed(const Duration(milliseconds: 300)); bool isOnline = false; if (kIsWeb) { // Web端走HTTP探测逻辑 final response = await http .head(Uri.parse('https://$_probeAddress/health')) .timeout(_probeTimeout); isOnline = response.statusCode >= 200 && response.statusCode < 300; } else { // 移动端/桌面端保留原有轻量DNS探测逻辑 final result = await InternetAddress.lookup(_probeAddress) .timeout(_probeTimeout); isOnline = result.isNotEmpty && result[0].rawAddress.isNotEmpty; } _controller.sink.add(isOnline ? ConnectionStatus.online : ConnectionStatus.offline); } on SocketException catch (_) { _controller.sink.add(ConnectionStatus.offline); } on TimeoutException catch (_) { _controller.sink.add(ConnectionStatus.offline); } catch (_) { _controller.sink.add(ConnectionStatus.offline); } } Future<void> close() async { await _connectionSubscription?.cancel(); await _controller.close(); } }
注意事项
- Web端做HTTP探测时,如果使用第三方公共地址,大概率会触发浏览器CORS跨域限制导致请求被拦截,出现离线误判,必须使用自有业务域名下的接口,且服务端配置好对应跨域响应头
- 探测超时时间建议设置在2-5秒区间,过短会在弱网环境下频繁误判,过长会导致网络状态更新延迟
connectivity_plus在Web端的状态监听基于浏览器原生online/offline事件,该事件仅能反映设备是否接入局域网,无法判断是否能正常访问公网或业务服务,必须搭配主动探测逻辑才能保证检测结果准确
内容的提问来源于stack exchange,提问作者Neal Osva
相关产品推荐
相关产品推荐

