添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

用户退出当前页面时,修改的数据未进行保存,需要发送接口请求实现自动保存的功能。简单分析需求可知,退出页面包含 路由切换 和 **关闭浏览器标签 **页两种情况:

  • 路由切换: 项目使用 Vue2 开发,离开页面时可以在 beforeDestroy 钩子函数中调用接口实现保存数据,但是这个方法只能在路由切换当前组件销毁前触发,无法监听到浏览器页面关闭的情况。
  • 关闭浏览器标签页: 考虑在 window.onunload 钩子函数中发送请求。
  • 路由切换时,当前组件将会被销毁,由于 beforeDestroy 钩子函数是在组件销毁前被调用,可以直接拿到当前组件的 data,因此可以在 beforeDestroy 钩子函数中直接使用 axios 去调用接口,保存数据。
    路由切换时调用接口保存数据的方式简单,不做过多赘述。

    关闭浏览器标签页

    请求时机:

    回顾一下浏览器加载、刷新、卸载(关闭)时触发的事件:

  • 加载时:触发 onload 事件
  • 刷新时:先触发 onbeforeunload 事件,然后是 onunload 事件,最后是 onload 事件。
  • 卸载时:先触发 onbeforeunload 事件,然后是 onunload 事件
  • 刷新和卸载页面时都会先后触发 onbeforeunload 和 onunload 事件,但刷新页面的时候时不需要调用接口的,那么就需要区分刷新和关闭行为。

    根据时间差来实现判断是刷新还是关闭标签:
    在点击刷新或者关闭时开始计时记录下这一刻的时间戳,因为刷新和关闭 在执行onunload方法时的时间不一样,一般情况下经过测试:

  • 关闭时时间差不大于3毫秒
  • 刷新时即使只有一个简单的helloworld页面都不少于10毫秒
  • 而一般网站网页内容更多,时间差达到了100多毫秒
  • mounted () {
      let beginTime = 0;
      let differTime = 0;
      window.onbeforeunload = function () {
        beginTime = new Date().getTime();
      window.onunload = function () {
        differTime = new Date().getTime() - beginTime;
        // 关闭页面操作
        if (differTime < 5) {
          // 请求接口数据
    
    接口调用方案

    由于 axios 库直接调用接口,后台无法收到请求,原因是当页面关闭销毁时,由于 axios 是异步的,http 请求就直接连接不上或者断开,导致无法向后台发送数据。
    解决思路是:ajax 请求换成同步的,或者保持 http 连接。
    ajax 设置为同步请求
    原生方式:

    var xhr = new XMLHttpRequest();
    //打开请求, open方法第三个参数设置为false为同步请求
    xhr.open('GET','js/data.json',false); //同步请求
    // 发送请求
    xhr.send(null);
    

    目前高版本浏览器都不建议使用 XMLHttpRequest 对象方式发送同步请求

    jQuery 方式:使用jq插件发送ajax请求时将 async 参数设置为 false 即可。
    keepAlive
    fetch 中设置 keepAlive 为 true 时,即使页面处于关闭状态也会保持连接,利用这个特性,可以发送可靠的请求。另外,使用 fetch 可以非常方便设置请求参数。

    fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      body: JSON.stringify({
        some: "data",
      // 保持连接
      keepalive: true,
    

    navigator.sendBeacon
    navigator.sendBeacon() 方法可用于通过HTTP将少量数据异步传输到Web服务器。会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:

  • 数据发送是可靠的。
  • 数据异步传输。
  • 不影响下一导航的载入。
  • navigator.sendBeacon(
      "/log",
      JSON.stringify({
        some: "data",
    

    sendBeacon API 不支持添加请求头,可以利用 Blob 做一些改动支持请求头。

    const blob = new Blob([JSON.stringify({ some: "data" })], {
        type: "application/json; charset=UTF-8",
    navigator.sendBeacon("/log", blob);
    

    sendBeacon 本意是发送信标,所以通常是在设置页面埋点时使用,并且不需要发送太多的数据。

    本文总结了用户退出当前页面前发送请求问题的一些解决方法,由于我的使用场景需要接口带上额外的参数和token,因此选择了使用 fetch api 设置 keepAlive 的方式实现退出该需求的。

    参考文档:
    如何处理页面关闭时发送HTTP请求
    fetch Api - MDN
    Navigator.sendBeacon()-MDN
    杂记:关于 navigator.sendBeacon 接口
    vue 判断窗口是关闭还是刷新 笔记
    vue监听浏览器刷新和关闭事件,并在页面关闭/刷新前发送请求