NetworkInterface.GetIsNetworkAvailable()仅检测本地网卡启用状态,不能判断实际联网能力;应结合带超时的HEAD请求(如https://connectivitycheck.gstatic.com/generate_204)验证,并复用HttpClient、后台周期探测、失败重试及状态缓存。

用 NetworkInterface.GetIsNetworkAvailable() 只能判断本地网卡是否启用,不能代表能上网
这个函数常被误用——它返回 true 仅表示有启用的网络适配器(比如 Wi-Fi 开着、网线插着),哪怕路由器断网、DNS 挂了、防火墙全拦,它照样返回 true。真实场景里,用户点按钮上传失败,查日志发现 GetIsNetworkAvailable() 返回 true,然后一脸懵。
实操建议:
- 别单独依赖
NetworkInterface.GetIsNetworkAvailable()做“能否联网”判断 - 它适合做快速前置过滤:如果它返回
false,那基本没戏;但返回true后必须继续验证 - 注意它不检查路由、NAT、代理或 IPv6/IPv4 可达性,纯属“物理层存在感”检测
真正靠谱的做法是发一个轻量 HTTP 请求测连通性
最直接的方式是向一个高可用、低延迟、无重定向、不依赖 CDN 的地址发起 HEAD 请求,比如 https://www.google.com/generate_204 或国内更稳的 https://connectivitycheck.gstatic.com/generate_204(Google 的连通性检查端点)。它返回 HTTP 204,响应体为空,速度快、干扰少。
实操建议:
- 用
HttpClient发起带超时的HEAD请求,超时设为 3–5 秒,避免卡 UI 或阻塞线程 - 检查响应状态码是否为
204,而不是只看有没有抛异常——有些网络中间件会返回 403 或 302,那也意味着不通 - 不要用
GET请求首页(如https://baidu.com),体积大、易受 DNS/CDN/证书影响,且百度可能返回 200 即使你实际被墙 - 避免硬编码域名,可配置备用地址(如加一个
https://msftconnecttest.com/redirect)防单点失效
异步检测时要注意 HttpClient 实例复用和生命周期
新手常在每次检测时 new 一个 HttpClient,短时间内高频调用会导致端口耗尽、DNS 缓存失效、连接不复用,最终出现 SocketException: Too many open files 或 HttpRequestException: Connection refused。
实操建议:
- 把
HttpClient声明为static readonly或注入为单例,全局复用 - 不要在方法内用
using var client = new HttpClient()——这会频繁新建销毁连接 - 如果项目用 .NET 6+,优先用
IHttpClientFactory管理,它自动处理 DNS 刷新、连接池和错误恢复 - 记得设置
client.Timeout,默认是 100 秒,对连通性检测来说太长
离线缓存与快速响应:别让用户等“检测结果”
用户点按钮时才开始测网络,体验差。更现实的做法是后台周期性探测(比如每 30 秒一次),把结果缓存在内存变量里,UI 直接读这个状态。否则每次操作前都等 3 秒请求,用户早切到别的 App 了。
实操建议:
- 用
Timer或PeriodicTimer启动后台探测,结果存进volatile bool _isOnline或AtomicBoolean-风格封装 - 首次启动时可同步触发一次探测,避免初始状态为假阳性
- 当检测失败时,别立刻标记为离线——连续失败 2–3 次再变状态,防偶发丢包误判
- 如果应用有登录态或数据同步逻辑,把网络状态和业务状态解耦:网络断了不等于要登出,只是暂停同步
HEAD 成功当成“永远在线”,或者把某次失败当成“彻底断网”。真实环境里,DNS 解析慢、TLS 握手卡住、HTTP/2 流控阻塞、代理认证弹窗……这些都不会反映在 IsNetworkAvailable 或一次简单请求里。










