整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

在用户离开页面时100%的发送 HTTP 请求

用户离开页面时可靠地发送 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 跳转。

个判断页面是否真的关闭和刷新的方法

入我的主页,查看更多JS的分享!

我的代码有多短,本篇内容就有多短!

本地存储对比:

  • sessionStorage,关闭窗口就被清除;
  • localStorage,一直存在直到手动删除;
  • cookie,设置有效期,可以直接实现标题的需求

今天不想多说话,直接贴上代码:

//判断是否支持 比如浏览器开启了隐私模式
var isCookie = () = >{
  return navigator.cookieEnabled;
};
//存储
function setCookie(cname, cvalue, exdays = 0) {
  cvalue = encodeURIComponent(JSON.stringify(cvalue));
  if (exdays > 0) {
    var d = new Date().getTime() + exdays * 24 * 3600 * 1000 + 8 * 3600 * 1000;
    var expires = "expires=" + new Date(d).toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
  } else {
    document.cookie = cname + "=" + cvalue + ";" + ";path=/";
  }
}
//获取
function getCookie(cname) {
  var name = cname + "=";
  var ca = document.cookie.split(";");
  for (var i = 0; i < ca.length; i++) {
    var c = ca[i];
    while (c.charAt(0) == " ") {
      c = c.substring(1);
    }
    if (c.indexOf(name) == 0) {
      let d = c.substring(name.length, c.length);
      return JSON.parse(decodeURIComponent(d));
    }
  }
  return "";
}
//获取 通过正则
// function getCookie(name) {
//   var arr,
//     reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
//   if ((arr = document.cookie.match(reg))) {
//     return JSON.parse(decodeURIComponent(arr[2]));
//   } else {
//     return null;
//   }
// }
//删除
function deleteCookie(name) {
  var date = new Date();
  date.setTime(date.getTime() - 1);
  var delValue = getCookie(name);
  if (delValue) {
    document.cookie = name + "=" + delValue + ";expires=" + date.toGMTString();
  }
}

使用示例:

//定义key
const tk = "tk2020";
const uk = "uk2020";
//保存
setCookie(tk, "14332239527007001", 0);
setCookie(uk, { id: 1, name: "以气御码" }, 0);
//获取
let token = getCookie(tk);
let user = getCookie(uk);
console.log(token);
console.log(user);

当使用setCookie时,传0或不传,表示关闭浏览器后就被清除,截图预览:

当登录的信息存储为这种形式,可以实现关闭浏览器,就清除登录信息。也可以再配合登录有效期,总不能“只要不关浏览器,就不退出登录了”。

文档:

  • MDN Cookie(https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie)
  • W3c Cookie(https://www.w3school.com.cn/js/js_cookies.asp)
  • 菜鸟教程 Cookie(https://www.runoob.com/js/js-cookies.html)
  • 有补充请在评论区留言。