保护你的编程猫账号。
新建一个假的xhr,把新xhr的属性都指向原xhr。例构造函数中的的代码:
for (let key in XHR) {
if (typeof XHR[key] == "function") {
this[key] = XHR[key].bind(XHR)
} else {
Object.defineProperty(this, key, { // 让新xhr的属性都指向原xhr
get() {
return XHR[key]
},
set(value) {
XHR[key] = value
},
configurable: true // 允许配置,使属性可以被重新定义,方便后期修改属性
})
}
}
重新定义open、send方法:
Object.defineProperty(this, "open", { // 如果前面没有设置`configurable: true`,这里就会报错,因为`open`已经被定义过了。
value: function (method, url) {
this.__url = url // 把参数存下来,方便在`send`中获取
this.__openArguments = arguments
XHR.open.apply(XHR, arguments)
}
})
Object.defineProperty(this, "send", {
value: function () {
onIntercept(this.__url, () => {
XHR.send.apply(XHR, arguments) // 如果没有要修改的,就用原xhr发送
}, reject, (callback) => {
modifyResponse(this, function (XHR) {
let { status, text } = callback({
status: XHR.status,
text: XHR.responseText
})
let result = {}
if (status != null) {
result.states = status
result.statesText = String(status)
}
if (text != null) {
result.response = text
result.responseText = text
}
return result
})
})
}
})
在修改请求时,不能用直接调用原xhr发送请求,因为原xhr上的事件监听器可能比此处的代码更早收到完成事件,这样这些事件监听器会获取到修改前的响应。此处则创建了一个新的xhr,并用新的xhr发送请求,并将请求修改后通过forgeResponse
构造响应。
function modifyResponse(XHR, callback) {
let originalXHR = new originalXMLHttpRequest() // 新建一个xhr发送请求
originalXHR.withCredentials = XHR.withCredentials
originalXHR.open.apply(originalXHR, XHR.__openArguments)
originalXHR.onreadystatechange = function () {
if (originalXHR.readyState == 4) {
// 收到请求后,把响应复制到假xhr上
for (let key of ["status", "statusText", "responseType", "response", "responseText"]) {
Object.defineProperty(XHR, key, {
value: originalXHR[key]
})
}
forgeResponse(XHR, callback(XHR)) // 修改响应并通知假xhr收到响应
}
}
originalXHR.send()
}
大佬xhr怎么劫持的,没看懂,能不能讲下思路