终于等到你!JS全新API支持关闭页面时安全发送网络请求

108 篇文章 2 订阅
10 篇文章 0 订阅
Chrome浏览器引入fetchLater()API,旨在解决在页面关闭或用户离开时安全发送数据的问题。这个API允许在指定时间点发送请求,即使页面已卸载,提供了更可靠的解决方案,替代了旧有的pagehide、visibilitychange等事件机制。
摘要由CSDN通过智能技术生成

在日常的开发中,经常需要在用户关闭页面或导航至其他页面时,向服务器发送重要的数据请求。然而,确保这些数据请求能够安全、完整地发送到后端一直是一个挑战。近日,Chrome 浏览器正在积极引入一个革命性的 JavaScript API——fetchLater()。这个全新的 API 旨在彻底简化关闭页面时的数据发送过程,确保即使在页面关闭后或用户离开的情况下,请求也能在未来某个时刻被安全、可靠地发出。本文就来详细了解这个超实用的全新 API。

注:fetchLater() 已在 Chrome 中提供,用于在版本 121(2024 年 1 月发布)开始的原始试验中供真实用户测试,该试验将持续到 Chrome 126(2024 年 7 月)。

以前这样写

在传统的做法中,开发者常常依赖pagehidevisibilitychangeunloadbeforeunload 事件来捕捉页面卸载的时机,并借助navigator.sendBeacon()方法或使用带有keepalive选项的fetch()来发送数据。

当页面卸载时,pagehide事件和 visibilitychange 事件会被触发。同时,visibilitychange事件会在页面的可见性发生变化时触发,这也可以用来捕捉页面卸载的情况。当用户即将离开当前页面(例如,尝试关闭浏览器标签页或刷新页面)时,beforeunload 事件被触发。

window.addEventListener('pagehide', (event) => {
  sendDataToServer();  
});  
  
window.addEventListener('visibilitychange', (event) => {
  if (document.visibilityState === 'hidden') {  
    sendDataToServer();  
  }  
});

addEventListener("unload", (event) => {
  sendDataToServer();  
})

addEventListener("beforeunload", (event) => {
  sendDataToServer();  
})

navigator.sendBeacon()方法用于异步地向服务器发送数据,即使页面正在卸载或不可见,也能保证数据被发送。这对于确保数据能够可靠地到达服务器非常有用。

function sendDataToServer() {  
  var url = 'https://example.com/log';  
  var data = new Blob(['some data'], {type: 'application/json'});  
    
  navigator.sendBeacon(url, data);  
}

当然,也可以使用fetch()的keepalive选项来确保请求在页面卸载后继续发送。不过需要注意的是,keepalive选项的支持情况可能因浏览器而异。

function sendDataToServer() {  
  var url = 'https://example.com/log';  
  var data = { someKey: 'someValue' };  
    
  fetch(url, {  
    method: 'POST',  
    body: JSON.stringify(data),  
    headers: {  
      'Content-Type': 'application/json'  
    },  
    keepalive: true // 尝试在页面卸载后继续发送请求  
  });  
}

然而,pagehidevisibilitychangeunloadbeforeunload 事件都存在可靠性问题。数据显示,即使多个事件一起使用,大约有 10% 的数据没有被发送就消失了。
在这里插入图片描述

妙用 fetchLater()

fetchLater()的功能正如其名:它要求浏览器在未来某个时刻确保发送请求,即使页面已经关闭或用户导航到其他页面。

fetchLater()的语法如下:

const fetchLaterResult = fetchLater(request, options);

fetchLater() 接受两个参数,与 fetchLater() 的参数相同:

  • request :可以是一个字符串形式的 URL,或者是一个 Request 实例。
  • options :可选项,它扩展了 fetchLater() 中的 options,并增加了一个名为 activateAfter 的超时设置。

fetchLater()返回一个 FetchLaterResult 对象,它目前只包含一个只读属性 activated。当指定的“稍后”时间点到来且请求已经发出时,activated 属性会被设置为 true。需要注意的是,对于 fetchLater() 发出的请求,其任何响应都不会被保留。

request

在使用时,最简单的形式是直接传入一个 URL 作为请求:

fetchLater('/endpoint/');

并且,fetchLater()继承了 fetch()的灵活性,允许用户为其请求设置多种选项。这些选项包括自定义头部信息、控制凭据的处理方式、指定 POST 请求体,以及利用 AbortController 在必要时取消请求。

fetchLater('/endpoint/', {
  method: 'GET',
  cache: 'no-store',
  mode: 'same-origin',
  headers: {Authorization: 'SUPER_SECRET'},
});

options

fetchLater()options 参数扩展了 fetch() 的选项,新增了 activateAfter 超时设置,使得请求能够在设定的超时时间后或页面卸载时(两者中较早发生者)自动触发。

例如,如果有一个应用,用户通常会在整个工作日中保持开启状态。在这种情况下,您可以设置一个一小时的超时时间,以确保在分析数据时拥有更精细的粒度,同时确保即使用户在这一小时内任何时候退出应用,也能够成功发送数据。随后,您可以为下一个小时的分析数据设置新的 fetchLater()请求,以确保数据的持续收集和发送。

const hourInMilliseconds = 60 * 60 * 1000;
fetchLater('/endpoint/', {activateAfter: hourInMilliseconds});

尝试 fetchLater()

目前,fetchLater() 仍处于实验状态,现在可以在 chrome://flags/#enable-experimental-web-platform-features 中启用 Experimental Web Platform 功能标志来启用 fetchLater()API。
在这里插入图片描述

在Vue应用中,当用户关闭页面(比如点击浏览器的“返回”按钮或者通过JavaScript直接调用`window.close()`),确实可能会遇到如何优雅处理未完成的异步请求的问题。为了确保这种情况下请求能够正常发送并且执行完毕,你可以采用以下策略: 1. **生命周期钩子**:Vue提供了一些生命周期钩子,在其中可以执行一些特定的操作。例如,在`beforeDestroy`钩子中,你可以发起一个阻止默认行为的事件,然后在该事件回调里发送数据到服务器。 ```javascript // 在组件内 beforeDestroy() { axios.post('/api/data', this.formData).then(() => { // 如果你想确保请求成功,可以设置超处理,如: setTimeout(() => { if (!this.$destroyed) { this.$emit('requestCompleted') // 或者自定义事件名 } }, 5000) }).catch(error => { console.error('Request failed:', error); // 发送失败的处理 }); } // 或者在全局混入或者某个服务中统一处理 new Vue({ beforeDestroy() { // 发起请求 } }); ``` 2. **自定义事件**:如果你的请求操作需要在整个应用范围内共享状态,可以在全局监听`beforeDestroy`触发的`requestCompleted`或者其他类似的事件,以确保所有请求都已完成。 3. **axios插件**:axios库本身提供了一个拦截器机制,可以捕获到所有的请求,包括那些在页面关闭前发出的。你可以在拦截器中添加逻辑来保存这些请求,并在适当的候取消它们。 4. **Promise.all**:如果你的应用中有多个并发请求,可以使用`Promise.all`来批量管理,确保所有请求完成后再退出。 ```javascript let pendingRequests = []; axios.post('/api/data', formData).then(() => { pendingRequests = pendingRequests.filter(request => !request.cancelled); // 取消已取消的请求 }).finally(() => { if (pendingRequests.length === 0) { window.close(); // 当所有请求完成后关闭页面 } }); // 其他请求同理... ``` 记得在实际项目中考虑用户体验,避免过度延迟用户的界面响应,如果请求非常重要但用户已明确不再关心结果,可以考虑是否真的需要在关闭发送请求
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值