惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Vulnerabilities – Threatpost
有赞技术团队
有赞技术团队
小众软件
小众软件
O
OpenAI News
C
Cyber Attacks, Cyber Crime and Cyber Security
I
Intezer
NISL@THU
NISL@THU
D
Darknet – Hacking Tools, Hacker News & Cyber Security
N
News and Events Feed by Topic
MongoDB | Blog
MongoDB | Blog
阮一峰的网络日志
阮一峰的网络日志
Hacker News: Ask HN
Hacker News: Ask HN
D
Docker
WordPress大学
WordPress大学
Security Archives - TechRepublic
Security Archives - TechRepublic
A
About on SuperTechFans
Stack Overflow Blog
Stack Overflow Blog
C
CERT Recently Published Vulnerability Notes
L
LINUX DO - 最新话题
Application and Cybersecurity Blog
Application and Cybersecurity Blog
M
MIT News - Artificial intelligence
Blog — PlanetScale
Blog — PlanetScale
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
V2EX
Hacker News - Newest:
Hacker News - Newest: "LLM"
G
Google Developers Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
G
GRAHAM CLULEY
S
Schneier on Security
T
Tor Project blog
Spread Privacy
Spread Privacy
PCI Perspectives
PCI Perspectives
Microsoft Security Blog
Microsoft Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
F
Fortinet All Blogs
L
Lohrmann on Cybersecurity
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
T
The Exploit Database - CXSecurity.com
TaoSecurity Blog
TaoSecurity Blog
Apple Machine Learning Research
Apple Machine Learning Research
T
Threat Research - Cisco Blogs
T
Troy Hunt's Blog
罗磊的独立博客

阮一峰的网络日志

科技爱好者周刊(第 396 期):互联网通信的替代方案 科技爱好者周刊(第 396 期):互联网通信的替代方案 - 阮一峰的网络日志 科技爱好者周刊(第 395 期):软件开发的第三种方式 科技爱好者周刊(第 395 期):软件开发的第三种方式 - 阮一峰的网络日志 科技爱好者周刊(第 393 期):脑腐状态 科技爱好者周刊(第 392 期):axios 投毒与好莱坞式骗术 科技爱好者周刊(第 391 期):AI 的贫富分化 科技爱好者周刊(第 390 期):没有语料,大模型就是智障 套壳中国大模型撑起500亿美元估值?扒一扒 Cursor 的"套壳"疑云 科技爱好者周刊(第 389 期):未来如何招聘程序员 科技爱好者周刊(第 388 期):测试是新的护城河 零安装的"云养虾":ArkClaw 使用指南 科技爱好者周刊(第 387 期):你是领先的 科技爱好者周刊(第 386 期):当外卖员接入 AI 字节全家桶 Seed 2.0 + TRAE 玩转 Skill 科技爱好者周刊(第 385 期):马斯克害怕中国车企吗? 智谱旗舰 GLM-5 实测:对比 Opus 4.6 和 GPT-5.3-Codex 科技爱好者周刊(第 384 期):为什么软件股下跌 科技爱好者周刊(第 383 期):你是第几级 AI 编程 Kimi 的一体化,Manus 的分层 科技爱好者周刊(第 382 期):独立软件的黄昏 AI native Workspace 也许是智能体的下一阶段 科技爱好者周刊(第 381 期):中国 AI 大模型领导者在想什么 科技爱好者周刊(第 380 期):为什么人们拥抱"不对称收益" 科技爱好者周刊(第 379 期):《硅谷钢铁侠》摘录 我如何用 AI 处理历史遗留代码:MiniMax M2.1 升级体验 科技爱好者周刊(第 378 期):预测是新的互联网热点 科技爱好者周刊(第 377 期):14万美元的贫困线 科技爱好者周刊(第 376 期):太空数据中心的争议 科技爱好者周刊(第 375 期):一扇门的 Bug 终于有人做了 Subagent,TRAE 国内版 SOLO 模式来了 科技爱好者周刊(第 374 期):6GHz 的问题 VS Code 使用国产大模型 MiniMax M2 教程 科技爱好者周刊(第 373 期):数据模型是新产品的核心 国产大模型接入 Claude Code 教程:以 Doubao-Seed-Code 为例 科技爱好者周刊(第 372 期):软件界面如何设计 大模型比拼:MiniMax M2 vs GLM 4.6 vs Claude Sonnet 4.5 科技爱好者周刊(第 371 期):一个乐观主义者的专访 科技爱好者周刊(第 370 期):正确的代码高亮 错误处理:异常好于状态码 科技爱好者周刊(第 369 期):Tim 与罗永浩的对谈 科技爱好者周刊(第 368 期):不要这样管理软件团队 一天之内,智谱和 Anthropic 都发了最强编程模型 科技爱好者周刊(第 367 期):Nano Banana 的几个妙用 科技爱好者周刊(第 366 期):旧金山疯狂的 AI 广告 科技爱好者周刊(第 365 期):流量变现正在崩塌 科技爱好者周刊(第 364 期):最难还原的魔方 科技爱好者周刊(第 363 期):最好懂的神经网络解释 科技爱好者周刊(第 362 期):GitHub 工程师谈系统设计 科技爱好者周刊(第 361 期):暗网 Tor 安全吗? 科技爱好者周刊(第 360 期):Dan Wang 的新书 科技爱好者周刊(第 359 期):Palantir 值得关注 科技爱好者周刊(第 358 期):如何拯救一家濒临倒闭的创业公司 扣子空间网页设计,是在挑战 V0 吗? 《唐纵日记》摘录 科技爱好者周刊(第 357 期):稳定币的博弈 科技爱好者周刊(第 356 期):公司强推 AI 编程,我该怎么办 科技爱好者周刊(第 355 期):两本《芯片战争》 科技爱好者周刊(第 354 期):8000mAh 手机电池,说明了什么? 科技爱好者周刊(第 353 期):苹果的"液态玻璃"是为了 AR 科技爱好者周刊(第 352 期):Bug 追踪系统的正确样子 科技爱好者周刊(第 351 期):GitHub Issues(几乎)是最好的笔记应用 科技爱好者周刊(第 350 期):Java 三十周年 科技爱好者周刊(第 349 期):神经网络算法的发明者 科技爱好者周刊(第 348 期):李飞飞,从移民到 AI 明星 科技爱好者周刊(第 347 期):冷启动的破解之道 科技爱好者周刊(第 346 期):未来就是永恒感的丧失 科技爱好者周刊(第 345 期):HDMI 2.2 影音可能到头了 科技爱好者周刊(第 344 期):制造业正在"零工化" 科技爱好者周刊(第 343 期):如何阻止 AI 爬虫 科技爱好者周刊(第 342 期):面试的 AI 作弊----用数字人去面试 科技爱好者周刊(第 341 期):低代码编程,恐怕不会成功 科技爱好者周刊(第 340 期):技术炒作三十年 科技爱好者周刊(第 339 期):代币是什么 科技爱好者周刊(第 338 期):重新思考 6G 科技爱好者周刊(第 337 期):互联网创业几乎没了 科技爱好者周刊(第 336 期):面对 AI,互联网正在衰落 科技爱好者周刊(第 335 期):年底的未来已来 科技爱好者周刊(第 334 期):年终笔记四则 科技爱好者周刊(第 333 期):一切都要支付两次 科技爱好者周刊(第 332 期):西蒙·威利森的年终总结,梁文锋的访谈 科技爱好者周刊(第 331 期):你可能是一个 NPC 科技爱好者周刊(第 330 期):李开复梳理人工智能 科技爱好者周刊(第 329 期):示意图利器 D2 科技爱好者周刊(第 328 期):AI 模型不是一门好生意 科技爱好者周刊(第 327 期):没有链接的互联网 科技爱好者周刊(第 326 期):世界没有那么多财富 科技爱好者周刊(第 325 期):VS Code 编辑器的下一站是 Zed? 科技爱好者周刊(第 324 期):人类已知的最大质数 科技爱好者周刊(第 323 期):技术公司的口号比拼 科技爱好者周刊(第 322 期):内容行业的内幕 科技爱好者周刊(第 321 期):傅盛回忆录 科技爱好者周刊(第 320 期):乒乓仓 科技爱好者周刊(第 319 期):如何拍出爆款视频 科技爱好者周刊(第 318 期):创业咖啡馆的记忆 科技爱好者周刊(第 317 期):驴子、老虎和狮子的寓言 科技爱好者周刊(第 316 期):你一生的故事 科技爱好者周刊(第 315 期):一份谷歌离职报告 科技爱好者周刊(第 314 期):《黑神话:悟空》可以产业化吗? 科技爱好者周刊(第 313 期):如果新加坡没有空调
如何用网页脚本追踪用户
阮一峰 · 2019-04-15 · via 阮一峰的网络日志

本文介绍如何编写 JavaScript 脚本,将用户数据发回服务器。

我做了一个代码仓库,包含了下面所有的例子,可以运行查看效果。

一、同步 AJAX

数据发回服务器的常见做法是,将收集好的用户数据,放在unload事件里面,用 AJAX 请求发回服务器。

但是,异步 AJAX 在unload事件里面不一定能成功,因为网页已经处于卸载中,浏览器可能发送,也可能不发送。所以,要改成同步 AJAX 请求。


window.addEventListener('unload', function (event) {
  let xhr = new XMLHttpRequest();
  xhr.open('post', '/log', false);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send('foo=bar');
});

上面代码中,xhr.open()方法的第三个参数是false,表示同步请求。

这种方法最大的问题在于,浏览器逐步将不允许在主线程上面,使用同步 AJAX。所以,上面代码实际上不能用。

二、异步 AJAX

异步 AJAX 其实是能用的。前提是unload事件里面,必须有一些很耗时的同步操作。这样就能留出足够的时间,保证异步 AJAX 能够发送成功。


function log() {
  let xhr = new XMLHttpRequest();
  xhr.open('post', '/log', true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send('foo=bar');
}

window.addEventListener('unload', function(event) {
  log();

  // a time-consuming operation
  for (let i = 1; i < 10000; i++) {
    for (let m = 1; m < 10000; m++) { continue; }
  }
});

上面代码中,强制执行了一次双重循环,拖长了unload事件的执行时间,导致异步 AJAX 能够发送成功。

三、追踪用户点击

setTimeout也能拖延页面卸载,保证异步请求发送成功。下面是一个例子,追踪用户点击。


// HTML 代码如下
// <a id="target" href="https://baidu.com">click</a>
const clickTime = 350;
const theLink = document.getElementById('target');

function log() {
  let xhr = new XMLHttpRequest();
  xhr.open('post', '/log', true);
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
  xhr.send('foo=bar');
}

theLink.addEventListener('click', function (event) {
  event.preventDefault();
  log();

  setTimeout(function () {
    window.location.href = theLink.getAttribute('href');
  }, clickTime);
});

上面代码使用setTimeout,拖延了350毫秒,才让页面跳转,因此使得异步 AJAX 有时间发出。

四、反弹追踪

追踪用户点击,还可以使用反弹追踪(bounce tracking)。

所谓"反弹追踪",就是网页跳转时,先跳到一个或多个中间网址,以便收集信息,然后再跳转到原来的目标网址。


// HTML 代码如下
// <a id="target" href="https://baidu.com">click</a>
const theLink = document.getElementById('target');

theLink.addEventListener('click', function (event) {
  event.preventDefault();
  window.location.href = '/jump?url=' + 
    encodeURIComponent(theLink.getAttribute('href'));
});

上面代码中,用户点击的时候,会强制跳到一个中间网址,将信息携带过去,处理完毕以后,再跳到原始的目标网址。

谷歌和百度现在都是这样做,点击搜索结果时,会反弹多次,才跳到目标网址。

五、Beacon API

上面这些做法,都会延缓网页卸载,严重影响用户体验。

为了解决网页卸载时,异步请求无法成功的问题,浏览器特别实现了一个 Beacon API,允许异步请求脱离当前主线程,放到浏览器进程里面发出,这样可以保证一定能发出。


window.addEventListener('unload', function (event) {
  navigator.sendBeacon('/log', 'foo=bar');
});

上面代码中,navigator.sendBeacon()方法可以保证,异步请求一定会发出。第一个参数是请求的网址,第二个参数是发送的数据。

注意,Beacon API 发出的是 POST 请求。

六、ping 属性

HTML 的<a>标签有一个ping属性,只要用户点击,就会向该属性指定的网址,发出一个 POST 请求。


<a href="https://baidu.com" ping="/log?foo=bar">
  click
</a>

上面代码中,用户点击跳转时,会向/log这个网址发一个 POST 请求。

ping属性无法指定数据体,似乎只能通过 URL 的查询字符串携带信息。

七、参考链接

(完)