应监听 online/offline 事件并结合主动 fetch 探测:页面加载时读取 navigator.onLine 初始值,绑定事件监听网络切换,再通过 HEAD 请求 /health 等 endpoint 验证服务可达性,避免仅依赖浏览器在线状态。

如何监听 navigator.onLine 的实时变化
navigator.onLine 是一个只读布尔值,但它**不会自动响应网络切换**——它只在页面加载时取一次初始值,之后除非手动触发或浏览器主动更新(如 Chrome/Firefox 在某些网络断开瞬间会同步更新),否则不会变。所以不能只靠轮询 navigator.onLine 来判断真实状态。
正确做法是监听全局的 online 和 offline 事件:
window.addEventListener('online', () => {
console.log('已联网');
});
window.addEventListener('offline', () => {
console.log('已离线');
});
- 这两个事件触发及时性依赖浏览器实现,Chrome 和 Firefox 支持较好;Safari 在某些 macOS/iOS 版本中对
offline响应有延迟甚至不触发 - 事件只反映“系统级网络接口是否可用”,不是“能否访问目标服务器”。比如 Wi-Fi 已连但路由器断网,
navigator.onLine仍为true - 页面刚打开时,建议先读一次
navigator.onLine,再绑定事件,避免错过初始状态
为什么单纯靠 online/offline 事件不够用
这些事件无法检测以下真实业务场景:
- Wi-Fi 连接正常,但 API 接口返回
503 Service Unavailable或超时 - 用户处于“飞行模式+手动开启 Wi-Fi”,
navigator.onLine为true,但实际无上行路由 - 企业内网环境,DNS 不通或代理拦截,导致 fetch 失败,但浏览器认为“在线”
因此必须结合主动探测:
立即学习“Java免费学习笔记(深入)”;
推荐用轻量 fetch 请求一个稳定、低开销的 endpoint(例如自己服务的 /health 或 https://www.google.com/generate_204):
async function checkServerReachable() {
try {
const res = await fetch('/health', { method: 'HEAD', cache: 'no-cache' });
return res.ok;
} catch (e) {
return false;
}
}
- 不要用 GET 请求图片或空资源,容易被缓存或触发 CORS
- 加
cache: 'no-cache'防止 Service Worker 或浏览器缓存干扰判断 - 避免高频轮询(如每秒一次),建议首次离线后延时 5–10 秒再探,或仅在用户操作前检查
离线时该做什么:缓存策略与 UI 反馈要点
检测到 offline 后,不能只弹个提示就结束。关键动作包括:
- 暂停所有非幂等请求(如 POST / PUT),把它们暂存到 IndexedDB 或 localStorage,等恢复后再重放
- 禁用依赖网络的交互控件(如提交按钮、搜索框),并用
aria-busy="true"或 CSS 类标明不可用状态 - 如果使用了 Service Worker,确保 precache 了核心静态资源(HTML/CSS/JS),否则离线时白屏
- 避免在
offline事件回调里直接调alert()—— 移动端可能被拦截,且打断用户操作流
UI 提示建议用轻量 toast,带明确恢复机制(如“重试”按钮),而不是全屏遮罩。
兼容性与移动端特殊行为注意点
Android WebView 和 iOS WKWebView 对 online/offline 事件支持不一致:
- 部分 Android 旧版 WebView 完全不触发这两个事件,需 fallback 到定时
fetch探测 - iOS Safari 在后台标签页中可能冻结 JS 执行,导致事件延迟数秒甚至丢失
- PWA 应用若注册了 Service Worker,可通过
self.registration.update()+waiting状态间接感知网络恢复(需配合 message channel) -
navigator.onLine在 Electron 中反映的是主进程网络状态,渲染进程需通过 IPC 同步
真正健壮的网络状态管理,永远是「事件监听 + 主动探测 + 业务层兜底」三层组合。别指望单个 API 解决所有问题。










