能,但不保证送达;keepalive: true 仅在页面卸载时尽力发送轻量、无副作用的请求(如埋点),不支持 safari,超 64kb、cors 预检或 formdata 等会静默失败,关键操作应改用 sendbeacon 或服务端兜底。

keepalive 选项在页面卸载时真的能发出去请求吗?
不能保证。浏览器对 keepalive: true 的支持有明确限制:它只在页面即将卸载(如用户关闭标签页、导航离开)时,让 fetch 请求“尽力发送”,但不等待响应,也不保证送达。Chrome 和 Firefox 支持该选项,Safari 目前完全不支持(截至 Safari 17.5),且即使在支持的浏览器中,若请求体过大(通常 > 64KB)、或触发 CORS 预检、或使用了某些 headers(如 Authorization),请求可能被静默丢弃。
什么场景下该用 keepalive,什么情况下不该用?
适合用于轻量级、非关键、无副作用的上报类请求,比如页面停留时长统计、错误日志快照、A/B 实验曝光埋点。不适合用于依赖响应结果的操作(如保存草稿、提交表单、支付确认),因为得不到 response,也无法重试或处理失败。
- ✅ 推荐:
fetch('/log', { method: 'POST', body: JSON.stringify({ event: 'unload', duration: 12345 }), keepalive: true }) - ❌ 避免:
fetch('/api/submit', { method: 'POST', body: bigFormData, keepalive: true })—— 表单数据大、需响应校验,应改用beforeunload+ 同步 XHR 或服务端兜底
keepalive 请求为什么经常发不出去?常见原因和检查点
不是代码写错,而是浏览器策略在起作用。最常踩的坑是:请求体类型和大小不合规。Fetch 的 keepalive 只接受 text/plain、application/x-www-form-urlencoded 或小体积的 application/json;如果用 FormData 或 Blob,会被拒绝(控制台无报错,但 Network 面板看不到请求)。
- 检查请求体是否超过 ~64KB —— 超过即丢弃
- 避免设置
Credentials: 'include'或自定义Authorizationheader —— 触发 CORS 预检,keepalive 请求不发预检 - 不要在
visibilitychange事件里调用 keepalive fetch —— 此时页面可能还没进入 unload 阶段,行为不可靠
替代方案比 keepalive 更可靠吗?
是的。对于必须送达的请求,优先考虑 navigator.sendBeacon():它专为卸载场景设计,支持任意序列化数据(自动转为 text/plain),最大 64KB,且兼容性更好(IE10+、所有现代浏览器)。唯一限制是只能 POST,且无法读取响应。
sendBeacon('/log', JSON.stringify({ event: 'unload' }))
如果你需要响应或更灵活的控制,就得放弃“卸载时发送”的幻想,改用主动保存策略:监听 beforeunload 做轻量同步保存(仅限简单数据),或结合 IndexedDB + 后台同步(BackgroundSync API),但后者需要 Service Worker 且支持度有限。
keepalive 不是万能钩子,它只是个尽力而为的逃生通道——别把它当主力,也别在 Safari 上测试它。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











