• Chrome不允许在页面关闭或导航跳转时发送同步请求


            在用户关闭页面,或跳转到其他页面时,需要向服务器发送请求。常规方案是在unload或者beforeunload事件中,使用XMLHttpRequest发送请求。

            默认情况下,XHR请求(使用fetch或XMLHttpRequest)是异步非阻塞的,一旦请求排队后,请求的实际处理就会移交浏览器。取决于网络连接、程序性能、服务器配置等等因素,极有可能在它即将发送时,页面已经卸载,从而导致发送失败或者发送被取消。

            为避免异步请求被取消,一种解决方式是换成同步XMLHttpRequest请求。但是,这会阻塞页面的卸载和跳转,导致屏幕出现“冻结”和无响应的用户体验。

            同时,Chrome/Edge浏览器已经不允许页面关闭期间,在如下事件中进行同步的XMLHttpRequest调用:beforeunload, unload, pagehide, 以及 visibilitychange
    Disallow sync XHR in page dismissal - Chrome Platform Status (chromestatus.com)

            为确保页面在卸载时将数据发送到服务器,官方建议使用sendBeacon()Fetch keep-alive

    Fetch keepalive

            Fetch API提供了一种处理服务器交互的强大方法,以及一个跨平台API使用的一致接口。keepalive选项设置为true,则即使发起该请求的页面已经终止,也能确保请求继续执行。
            chrome浏览器有负载限制:64KB。请求为"高"优先级。

    1. window.addEventListener('unload', {
    2. const data = { username: 'example' };
    3. fetch('/xxxurl', {
    4. method: 'POST',
    5. headers: {
    6. 'Content-Type': 'application/json',
    7. },
    8. body: JSON.stringify(data),
    9. keepalive: true
    10. });
    11. });

            Body可以是如下任意类型:ArrayBuffer,ArrayBufferView,Blob/File,string,URLSearchParams,FormData

    1. var postdata = {};
    2. postdata["username"] = "example";
    3. postdata["password"] = "123";
    4. formBody = new URLSearchParams();
    5. for(let k in postdata) {
    6. if(typeof(postdata[k]) === 'object') {
    7. formBody.append(k, JSON.stringify(postdata[k]));
    8. } else {
    9. formBody.append(k, postdata[k]);
    10. }
    11. }
    12. const options = {
    13. credentials: 'include',
    14. method: 'POST',
    15. headers: {
    16. "Content-type": "application/x-www-form-urlencoded; charset=UTF-8",
    17. },
    18. body: formBody,
    19. keepalive: true
    20. }
    21. fetch('/url', options);

    Navigator.SendBeacon()

            SendBeacon实际底层使用的是Fetch API。所以可以确保页面卸载后请求继续,也同样具有chrome浏览器有64KB的负载限制。只能发送POST请求。请求为"最低"优先级。
            数据可以是如下任意类型:ArrayBuffer,ArrayBufferView,Blob,DOMString,FormData,URLSearchParams。
            自定义请求头Content-Type必须是以下三种之一:
            "text/plain","application/x-www-form-urlencoded","multipart/form-data"

            如果数据类型是DOMString,则默认Content-Type为"text/plain":

    navigator.sendBeacon(url, data);

           如果数据类型是Blob,则Content-Type一般设置为"application/x-www-form-urlencoded":

    1. const blob = new Blob([JSON.stringify(data), {
    2. type: 'application/x-www-form-urlencoded',
    3. }]);
    4. navigator.sendBeacon(url, blob);

            如果想要以"application/json"的形式发送数据,则需要使用Blob适当调整:

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

            如果数据类型是FormData,则直接创建FormData,此时Content-Type会自动设置为"multipart/form-data":

    1. const formData = new FormData();
    2. for(let k in postdata) {
    3. if(typeof(postdata[k]) !== 'string') {// formData只能append string 或 Blob
    4. formData.append(k, JSON.stringify(postdata[k]));
    5. } else {
    6. formData.append(k, postdata[k]);
    7. }
    8. }
    9. navigator.sendBeacon(action, formData);

    参考:
    https://zhuanlan.zhihu.com/p/532162177
    https://blog.csdn.net/qq_29722281/article/details/125553696
     

  • 相关阅读:
    计算机毕业设计——基于html汽车商城网站页面设计与实现论文源码ppt(35页) HTML+CSS+JavaScript
    软件测试测试常见分类有哪些?
    KSO - docker部署Rabbitmq的详细讲解以及各种隐藏坑
    【报错】overleaf不能成功编译中文(在线latex)
    2.TCP/IP协议系统
    希望所有计算机专业同学都知道这些老师
    Google Earth Engine(GEE)——多源遥感变量筛选(PCA主成分分析),变量筛选/降维处理
    性能测试中,TPS和RT之间的关系,你知道吗?
    zeppelin安装python(使用pymysql包)
    【无标题】
  • 原文地址:https://blog.csdn.net/EvelynHouseba/article/details/126120242