拦截xhr
1// 重写 xhr 拦截异常然后上报
2const trackerXHR = () => {
3 // 拿到 XMLHttpRequest
4 let XMLHttpRequest = window.XMLHttpRequest
5 // 保存原有的open方法
6 let XMLOriginOpen = XMLHttpRequest.prototype.open
7 // 重写 open 方法 目的是为了保存 ethods, url 这个参数的值 用于埋点上报
8 // 不能用箭头函数
9 // 1. 箭头函数没有 arguments
10 // 2. 箭头函数会改变指向 我们需要将 this指向 XMLHttpRequest
11 // 3. 箭头函数this绑定的是上一层的this
12 XMLHttpRequest.prototype.open = function (methods, url, async) {
13 // 将值挂在XMLHttpRequest.logData 中
14 this.logData = {
15 methods,
16 url
17 }
18 // 执行原有的open方法
19 return XMLOriginOpen.apply(this, arguments)
20 }
21 // 保留原有的send方法
22 let XMLOriginSend = XMLHttpRequest.prototype.send
23 XMLHttpRequest.prototype.send = function (request) {
24 // 重写load、error、abort方法
25 // 为什么不修改load、error、abort的原型了呢
26 // 因为用户有时候可能不会去调用 load、error、abort 方法,去执行他们的回调
27 // 比如 xhr.load、xhr.error、xhr.abort 等等
28 // 如果不执行回调 就无法达成上报的目的 但是 send 是一定会执行的
29 // 所以放到 send 里 去监听
30 const startTime = new Date() // 计算接口的duration, send 时记录请求时刻
31 const handle = (eventType) => {
32 return () => {
33 // 上报 status 不为 0 的错误
34 if (
35 (eventType === 'load' && this.response.status !== 0) ||
36 eventType === 'error' ||
37 eventType === 'abort'
38 ) {
39 const duration = new Date() - startTime
40 const log = {
41 duration,
42 status: this.status,
43 statusText: this.statusText,
44 url: this.responseURL,
45 method: this.logData.methods,
46 params: request,
47 response: JSON.stringify(this.response || ''),
48 type: 'xhr',
49 eventType
50 }
51 // 拿到之后去上报
52 console.log(log, 'log----')
53 }
54 }
55 }
56 this.addEventListener('load', handle('load'), false)
57 this.addEventListener('error', handle('error'), false)
58 this.addEventListener('abort', handle('abort'), false)
59 return XMLOriginSend.apply(this, arguments)
60 }
61}
62trackerXHR()
个人笔记记录 2021 ~ 2025