keepalive: true 是浏览器唯一支持页面卸载后发送请求的机制,它不保证成功,仅让浏览器尽力在后台完成发送;适用于 post/put/delete 等带 body 请求,需在卸载前同步调用,不支持 await 或回调。

不能 100% 确保完成,但 keepalive: true 是目前浏览器唯一支持的、能在页面卸载后继续发送请求的机制;它不保证成功,只让浏览器“尽力而为”地发出去。
为什么 keepalive: true 是唯一可行方案
页面调用 window.location、location.replace() 或触发导航(如点击链接、关闭标签页)时,JavaScript 执行环境会快速终止。常规 fetch()、XMLHttpRequest、甚至 setTimeout 回调都会被强制中止。
keepalive: true 是 Fetch API 的特殊标记,告诉浏览器:“这个请求很重要,即使页面已进入 terminated 状态,也请在后台线程中完成发送”。浏览器会将其移交至网络栈独立处理,不依赖 JS 上下文。
- 仅适用于
POST、PUT、DELETE等有 body 的请求(GET 不允许带 body,且语义上不适合日志/上报) - 必须在页面卸载前调用(例如
beforeunload、pagehide、或跳转前的同步代码中) - 不支持
await或.then()—— 调用即“发射”,后续无回调可监听 - Chrome、Firefox、Edge 支持;Safari 从 v15.4+ 开始支持,旧版 Safari 会静默忽略
实际怎么写才不会白发
直接在跳转/卸载逻辑里发请求,别等异步、别加 try/catch、别依赖返回值:
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
function logBeforeLeave() {
fetch("/api/track", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ event: "page_exit", url: window.location.href }),
keepalive: true
});
// ✅ 正确:立刻跳转,不等 fetch 完成
window.location.href = "/thank-you";
}
- 不要写
await fetch(...)—— 页面一跳转,Promise 就被取消 - 不要在
beforeunload里 return 提示字符串来“阻塞跳转”再发请求 —— 阻塞期间发的请求仍可能被中断,且现代浏览器已限制该行为 - 推荐用
pagehide事件替代beforeunload,因为它更可靠地覆盖了缓存还原、标签页隐藏等场景 - 服务端需容忍重复请求 —— 因为浏览器无法确认是否真正送达,重试机制可能触发多次
常见失败原因和绕不过的坑
即使写了 keepalive: true,请求仍可能丢失。典型原因包括:
- 请求体过大(Chrome 限制约 64KB)—— 超出部分会被截断,服务端收不到完整数据
- 目标域名未配置 CORS,且请求含 credentials(如 cookie)——
keepalive请求仍受 CORS 约束,跨域失败时静默丢弃 - 用户强制 kill 浏览器进程(非正常关闭)—— 操作系统层面终止,浏览器无机会发送
- 移动端后台进程被系统回收(尤其 Android)—— 即使页面刚退到后台,请求也可能被杀掉
- 使用了
redirect: "follow"——keepalive请求不支持自动重定向,遇到 302 会失败
所以关键不是“怎么让它必达”,而是“怎么设计得能容忍丢失”:比如把关键日志拆成轻量事件(visibilitychange + pagehide 双触发)、服务端做幂等去重、前端 fallback 到 localStorage 缓存未发数据(下次启动时补发)。
最常被忽略的一点:keepalive 不是连接复用(那是 HTTP/1.1 的 Connection: keep-alive),也不是长连接维持;它只是浏览器对“临终请求”的一种尽力派送机制 —— 写的时候就要接受它不可观测、不可等待、不可重试。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










