在用户离开页面时可靠地发送 HTTP 请求

447次阅读  |  发布于2年以前

在用户离开页面时可靠地发送 HTTP 请求

当浏览器内多页面发生跳转时,无法保证当前页面进程内的请求能够顺利完成,大多数情况下,这些请求会被浏览器 cancled,此时请求还未到达后端服务器。这些请求的可靠性可能取决于以下几点:网络连接速度、应用程序性能,甚至外部服务本身的配置。

因此,在这时发送数据并不能可靠的传达给后端,如果我们依赖依赖这些日志来做对业务数据进行分析,可能会丢失一些数据。

可以尝试用代码解决上述问题:

document.getElementById('link').addEventListener('click', (e) => {
  e.preventDefault();

  fetch("/log", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    }, 
    body: JSON.stringify({
      name: 'FedJavaScript'
    }),
  });

  window.location = e.target.href;
});

但 fetch 会被加入异步队列,页面跳转时队列中剩余的请求仍会被 cancled。

那我们等待请求完成之后再 location 不就行了吗?

document.getElementById('link').addEventListener('click', async (e) => {
  e.preventDefault();

  await fetch("/log", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    }, 
    body: JSON.stringify({
      name: 'FedJavaScript'
    }),
  });

  window.location = e.target.href;
});

可以是可以,但移动端 300ms 但延迟都能有明显感受,万一 "/log" 接口返回太慢,用户就会感觉网站很卡。

好在目前前端都是现代浏览器,fetch 提供了 keepalive 参数来处理这个问题:

document.getElementById('link').addEventListener('click', (e) => {
  fetch("/log", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    }, 
    body: JSON.stringify({
      name: 'FedJavaScript'
    }),
    keepalive: true
  });
});

不需要我们阻止默认行为,也不需要 location 跳转。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8