如何在浏览器关闭发送请求

有的,我们需要在页面关闭时,统计用户在该网站浏览时长;有时需要告知后台,该用户已离开...
遇到这样的情况并不少见。

只是在此之前,有两件很重要的事情需要区分开来:

  • 如何知道浏览器是 关闭 还是 刷新
  • 关闭时发送请求,使用哪种 请求方式 才好

页面的生命周期函数

当前有两种表示方式

  • 页面生命周期函数

    • DOMContentLoaded —— 浏览器加载 HTML,并构建 DOM 树,但像 和样式这样的资源可能还没有加载。
    • load —— 浏览器加载所有资源(图像,样式等)。
    • beforeunload/unload —— 当用户离开页面时。
  • Page Visibility API 教程,Page Lifecycle API 教程
    • Active 阶段 网页处于可见状态,且拥有输入焦点
    • Passive 阶段 只可能发生在桌面同时有多个窗口的情况。
    • Hidden 阶段 用户的桌面被其他窗口占据,网页不可见
    • Terminated 阶段 由于用户主动关闭窗口,或者在同一个窗口前往其他页面,导致当前页面开始被浏览器卸载并从内存中清除
    • Frozen 阶段 网页处于 Hidden 阶段的时间过久,用户又不关闭网页,浏览器就有可能冻结网页,使其进入 Frozen 阶段。不过,也有可能,处于可见状态的页面长时间没有操作,也会进入 Frozen 阶段
    • Discarded 阶段 处于 Frozen 阶段,用户又不唤醒页面,那么就会进入 Discarded 阶段,即浏览器自动卸载网页,清除该网页的内存占用。不过,Passive 阶段的网页如果长时间没有互动,也可能直接进入 Discarded 阶段

判断浏览器是 关闭 还是 刷新

用来判断用户是否离开

通过三种方式来进行判断

  • beforeunload/unload
  • Terminated 阶段
  • 两者结合判断

理论知识够了,开始进行尝试
在此之前,由于页面关闭时,很多方法执行不了,只能通过连接后台进行判断,而且也很准确

var url = "http://127.0.0.1:3000/logout";
function getAajx(url) {var client = new XMLHttpRequest();client.open("get", url, false); // 第三个参数表明是同步的 xhrclient.setRequestHeader("Content-Type", "text/plain;charset=UTF-8");client.send();
}
function postAajx(url, data) {var client = new XMLHttpRequest();client.open("post", url, false); // 第三个参数表明是同步的 xhrclient.setRequestHeader("Content-Type","application/x-www-form-urlencoded");client.send(data);
}

beforeunload/unload

当浏览器窗口关闭或者刷新时,会触发beforeunload事件。当前页面不会直接关闭,可以点击确定按钮关闭或刷新,也可以取消关闭或刷新

由于刷新和关闭都会执行这个方法,因而在beforeunload/unload 中无法进行区分,下面是网友们的各种思路

  • 鼠标的位置,由于需要点击关闭按钮,因而鼠标不会在窗口内
window.addEventListener('beforeunload', function () {var n = window.event.screenX - window.screenLeft;var b = n > document.documentElement.scrollWidth - 20;if ((b && window.event.clientY < 0) || window.event.altKey) {alert("是关闭而非刷新");window.event.returnValue = ""; //这里可以放置你想做的操作代码} else {alert("是刷新而非关闭");}
}, false)

可惜执行不了,主要利用关闭刷新都会执行 onbeforeunload方法

  • 利用刷新跟关闭在不同浏览器中执行的方式不同1,2
var _beforeUnload_time = 0;
var _gap_time = 0;
var is_fireFox = navigator.userAgent.indexOf("Firefox") > -1; //是否是火狐浏览器
window.addEventListener("unload",function() {_gap_time = new Date().getTime() - _beforeUnload_time;if (_gap_time <= 5) {postAajx(url, `msg=浏览器关闭&time=${_gap_time}`);} else {postAajx(url, `msg=浏览器刷新&time=${_gap_time}`);}},false
);
window.addEventListener("beforeunload",function() {_beforeUnload_time = new Date().getTime();if (is_fireFox) {postAajx(url, `msg=火狐关闭&time=${_gap_time}`);}},false
);

可以看出,确实是可行,刷新时长都超过 5s,关闭在 5s内。基于Chrome浏览器

需要更多地去验证每个浏览器的细微差别,若是随着浏览器的不断升级,将来标准统一,有可能就没有这样的细微区别,导致执行不了

Terminated 阶段

借助Page Lifecycle API,Page Visibility API 教程,Page Lifecycle API 教程,网友

const getState = () => {if (document.visibilityState === "hidden") {return "hidden";}if (document.hasFocus()) {return "active";}return "passive";
};// Stores the initial state using the getState() function (defined above).
let state = getState();// Accepts a next state and, if there's been a state change, logs the
// change to the console. It also updates the state value defined above.
const logStateChange = nextState => {const prevState = state;if (nextState !== prevState) {console.log(`State change: ${prevState} >>> ${nextState}`);getAajx(url+ "?origin=" + nextState);state = nextState;}
};// These lifecycle events can all use the same listener to observe state
// changes (they call the getState() function to determine the next state).
["pageshow", "focus", "blur", "visibilitychange", "resume"].forEach(type => {window.addEventListener(type, () => logStateChange(getState()), {capture: true});}
);// The next two listeners, on the other hand, can determine the next
// state from the event itself.
window.addEventListener("freeze",() => {// In the freeze event, the next state is always frozen.logStateChange("frozen");},{ capture: true }
);window.addEventListener("pagehide",event => {if (event.persisted) {// If the event's persisted property is true the page is about// to enter the page navigation cache, which is also in the frozen state.logStateChange("frozen");} else {// If the event's persisted property is not true the page is// about to be unloaded.logStateChange("terminated");}},{ capture: true }
);

由于各个浏览器显示不同,上述效果不是很准确,特意使用 PageLifecycle.js再重新梳理一遍

<script src="./dist/lifecycle.es5.js"></script>
<script>console.log(window)lifecycle.addEventListener('statechange', function(event) {console.log(event.oldState, event.newState);getAajx(url+'?origin='+event.oldState+'>>>'+event.newState)});
</script>

很遗憾,刷新跟关闭一样,依旧无法判断出来。

综上: 目前真的只能靠 方案一:beforeunload/unload 时间来进行判断了

使用什么方式进行请求

  • img 动态创建img 利用 src属性进行通知,同理script的src应该也可以
  • XMLHttpRequest 同步发送ajax请求(上述例子便是如此操作)
  • navigator.sendBeacon() sendBeacon 这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向web服务器发送数据
// 兼容性
navigator.sendBeacon = navigator.sendBeacon || new Function('var r = new XMLHttpRequest();r.open("POST",arguments[0],true);r.send(arguments[1]);');function postForm (url, data) {let P = new FormData()P.append('origin', data.origin)navigator.sendBeacon(url, P)
}
lifecycle.addEventListener('statechange', function(event) {// getAajx(url+'?origin='+event.oldState+'>>>'+event.newState)postForm(url, {origin: event.oldState+'>>>'+event.newState })
});

也是可以发送请求的,由于异步,所以跟同步的ajax不同,但是这个确实更合理

总结

  • 浏览器刷新 关闭 目前只能通过时间大小来判断了,不完美
  • 发送请求 navigator.sendBeacon这个会更好

转载于:https://www.cnblogs.com/sinosaurus/p/10509369.html

如何在浏览器关闭发送请求相关推荐

  1. 谷歌浏览器怎么重发请求_Googel 浏览器 模拟发送请求工具--Advanced REST Client

    Advanced REST Client是 Chrome 浏览器下的一个插件,通过它可以发送 http.https.WebSocket 请求.在 Chrome 商店下搜索 Advanced REST  ...

  2. 浏览器发送请求过程解析

    HTTP协议是B/S体系结构应用程序的基础,只有了解了HTTP协议,才能理解如何在B/S体系结构下实现应用程序的国际化. 1.HTTP请求 当用户在浏览器的地址栏中输入一个URL并按回车键之后,浏览器 ...

  3. 浏览器开发工具请求头与响应头属性介绍

    HTTP 协议的 Header 是一块数据区域,分为请求头和响应头两种类型,客户端向服务区发送请求时带的是请求头,而服务器响应客户端数据时带的是响应头. 请求头里主要是客户端的一些基础信息,UA(us ...

  4. 浏览器HTTP协议请求头信息

    通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息.客户端向服务器发送一个请求,请求头包含请求的方法.URI.协议版本.以及包含请求修饰符.客户信息和内容的类似于MIME的消息结构 ...

  5. vue监听浏览器刷新和关闭事件,并在页面关闭/刷新前发送请求

    vue监听浏览器刷新和关闭事件,并在页面关闭/刷新前发送请求 1.需求背景: 2.需求分析: 3.实现方式: 4.实现方式解析: 1)浏览器页面事件基础 2)在mounted监听beforeunloa ...

  6. 浏览器如何发送ajax请求,浏览器关闭时,发送ajax请求

    浏览器关闭时,发送ajax请求 发布于:2018.11.12 - 13:10 当用户在浏览器关闭时,向服务器后台发送ajax请求.代码如下. 测试结果:Safari浏览器不支持,其余浏览器支持. if ...

  7. js监测页面关闭发送Ajax请求(浏览器关闭注销用户,清空session)

    说明: 需求为页面关闭发送一个ajax请求,使关闭浏览器及时清空session(浏览器关闭session并不会清空) 网站同时只能一个用户登录,同一账号后登录的用户不能把前一个登录的用户踢下线,有一个 ...

  8. 浏览器的一个请求从发送到返回都经历了什么?

    浏览器输入url经历图 分析过程: 1.用户输入url,浏览器内部代码将url进行拆分解析 url解析图 2.浏览器首先去找本地的hosts文件,检查在该文件中是否有相应的域名.IP对应关系,如果有, ...

  9. 解决浏览器 Provisional headers are shown 无法向后台发送请求问题

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 我的情况和下面情况一样,有一个断点. 今天调试项目BUG,页面的一个按钮点击后页面无反应,去后台找对 ...

最新文章

  1. php连接kafka集群,Kafka集群环境配置
  2. python复数类型-python复数类型
  3. python爬虫实战案例-Python爬虫实战案例:手机APP抓包爬虫
  4. 《Android的设计与实现:卷I》——第2章 框架基础JNI
  5. 给你总结了这些对付幂等性的套路
  6. c python通信protobuf_python 处理protobuf协议
  7. 关于Java成员变量、局部变量、方法,在JVM的内存空间分配
  8. Hibernate 系列 02 - Hibernate介绍及其环境搭建
  9. access mysql连接字符串_[数据库连接字符串] Access 连接字符串
  10. zz 跟风小结一下孕期~
  11. 递归法:递归实现排列型
  12. v4l2接口,结构图
  13. python矩阵连乘_python动态规划解决矩阵连乘
  14. /*深度优先建立深林,孩子兄弟法*/
  15. 《Adobe After Effects CC 2017 经典教程》资源下载地址
  16. 华为m40怎么升级鸿蒙,华为再亮剑,这四款手机将支持升级鸿蒙系统,网友:够给力!...
  17. python做视频剪辑_用python进行视频剪辑
  18. 函数的概念三要素参数返回值好处递归
  19. 太酷了,手把手教你用 Python 绘制桑基图
  20. three.js中jsm文件夹的使用

热门文章

  1. 微信小程序 实现简单发布信息
  2. Axure中继器的总结
  3. 新能源汽车兴起,神州租车成为新能源发展的重要推手
  4. 5g时代的到来,软件测试有多重要!
  5. Scala 优雅的异常处理之 try 与 Try
  6. 7-1 高速公路超速处罚 (15 分)
  7. bugku 简单套娃
  8. Tableau-多边形地图、设置地理信息、背景图地图
  9. 滚动条插件 nicescroll 的使用
  10. 以下这些识别手写文字图片的软件你都知道吗