浏览器返回操作,浏览器缓存导致不重新请求接口,数据不刷新解决方案

1,553 阅读1分钟
  • 先说结论,以下是可行的方法

    • 1.添加参数让每次请求不一样,如 new Date().getTime()Math.random()
    • 2.jQuery 请求设置 cache: false
    • 3.设置 xhr.setRequestHeader("Cache-Control", "no-cache") 或者 xhr.setRequestHeader("If-Modified-Since", "0")
    function initData() {
        $.ajax({
            type: 'GET',
            url: 'https://iiter.cn/api/soup',
            dataType: 'json',
            // cache: false,
            data: {
                // t: new Date().getTime()
                // t: Math.random()
            },
            beforeSend: function(xhr) {
                // xhr.setRequestHeader("Cache-Control", "no-cache");
                // xhr.setRequestHeader("If-Modified-Since", "0")
            },
            success: function(res) {
                console.log(res.data);
            }
        });
    }
    initData();
    

    五处注释对应五种方法,任意一种即可。

  • 问题

    • 页面上有一个按钮,按钮是否可以点击由服务器返回;用户点击按钮发送请求后,按钮变成不可点击状态;这个时候如果用户点击跳转到其他页面,然后再返回回来,会发现按钮又变成可点击的状态了。虽然服务器会兜底校验,但是这样容易让用户困扰,所以需要解决。
  • 测试环境

    • Google Chrome 版本 100.0.4896.127(正式版本) (x86_64)
    • 注意:我在调试过程中,打开控制台后即使取消勾选 Disable Cache ,也会刷新页面,可能是我设置的问题,所以调试过程中不要打开浏览器控制台,查看接口请求情况可以使用抓包工具查看
  • 网上查到的解决方法

    window.addEventListener('pageshow', function(event) {
        if (event.persisted || window.performance && window.performance.navigation.type == 2) {
            // do somethineg...
        }
    }, false);
    
  • 这里简单写个 demo ,用到的接口是之前收藏的免费接口,本地可以直接请求

    • 接入
      function initData() {
          alert('initData');
      }
      initData();
      window.addEventListener('pageshow', function(event) {
          if (event.persisted || window.performance && window.performance.navigation.type == 2) {
              initData();
          }
      }, false);
      
      • 执行结果:打开 A 页面,alert 一次,之后跳转到 B 页面,再次返回, alert 两次
      • 结论:返回操作,会重新渲染页面,执行页面 js ;按说这样就不会出现上边提到的问题,下面我们把 alert 换成 ajax 请求再试试;
    • 再次接入
      function initData() {
          $.ajax({
              type: 'GET',
              url: 'https://iiter.cn/api/soup',
              dataType: 'json',
              data: {},
              success: function(res) {
                  console.log(res.data);
              }
          });
      }
      initData();
      window.addEventListener('pageshow', function(event) {
          if (event.persisted || window.performance && window.performance.navigation.type == 2) {
              initData();
          }
      }, false);
      
      • 执行结果:重复 A 页面到 B 页面,再从 B 页面返回,抓包发现只有在 A 页面首次加载的时候,才会发起请求
      • 结论&猜测:这不和上一次的运行结果矛盾了吗? initData 方法应该会重新执行的,为什么没发现重新发出请求呢?猜测浏览器可能在请求一样的情况下,就不会重新发出请求,而是直接使用缓存的旧数据。再改写一下 demo 测试一下。
    • 再再次接入
      function initData() {
          $.ajax({
              type: 'GET',
              url: 'https://iiter.cn/api/soup',
              dataType: 'json',
              data: {
                  t: new Date().getTime()
              },
              success: function(res) {
                  console.log(res.data);
              }
          });
      }
      initData();
      window.addEventListener('pageshow', function(event) {
          if (event.persisted || window.performance && window.performance.navigation.type == 2) {
              initData();
          }
      }, false);
      
      • 执行结果,重复,发现一共发出了三次请求,情况和第一次接入效果吻合,可以确定第二次的猜测成立。但是这样重复请求,有些浪费资源,再优化一下
    • 再再再次接入
      var ajax_count = 0;
      function initData() {
          $.ajax({
              type: 'GET',
              url: 'https://iiter.cn/api/soup',
              dataType: 'json',
              data: {
                  t: ajax_count
              },
              success: function(res) {
                  console.log(res.data);
              }
          });
      }
      initData();
      window.addEventListener('pageshow', function(event) {
          if (event.persisted || window.performance && window.performance.navigation.type == 2) {
              ajax_count = localStorage.getItem('ajax_count') ? localStorage.getItem('ajax_count') : 0;
              ajax_count = ajax_count - 0 + 1;
              localStorage.setItem('ajax_count', ajax_count);
              initData();
          }
      }, false);
      
      • 执行结果:一开始是没使用 localStorage ,发现只有第一次操作是正常的,后面又不会重新请求接口了。猜测只要是重复了的,就不会再重新请求,所以使用 localStorage 存一下,保证每次都是不同的,得到了想要的结果。
    • 最终优化
      function initData() {
          $.ajax({
              type: 'GET',
              url: 'https://iiter.cn/api/soup',
              dataType: 'json',
              data: {
                  t: new Date().getTime()
              },
              success: function(res) {
                  console.log(res.data);
              }
          });
      }
      initData();
      
      • 结论:发现完全可以不使用网上查到的 pageshow ,只要保证每次请求参数不同就可以了。
  • 踩坑经验

    • 浏览器返回操作会重新渲染页面、执行所有 js ,但是只要是浏览器曾经请求过的接口,就不会重新请求,而是使用缓存的旧数据,这时候就要通过修改请求参数,实现想要的效果。