XHR 提交劫持与内容监听
本章将学会如何监听 XmlhttpRequest
的返回内容。
内容监听
这是我在国外网站找到的一个小例子
function addXMLRequestCallback(callback) {
var oldSend, i;
if (XMLHttpRequest.callbacks) {
XMLHttpRequest.callbacks.push(callback);
} else {
XMLHttpRequest.callbacks = [callback];
oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
for (i = 0; i < XMLHttpRequest.callbacks.length; i++) {
XMLHttpRequest.callbacks[i](this);
}
return oldSend.apply(this, arguments);
};
}
}
addXMLRequestCallback(function (xhr) {
xhr.addEventListener("load", function () {
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseURL);
}
});
});
使用是通过调用 addXMLRequestCallback
传入我们的劫持函数来实现,我们的劫持函数会收到一个 xhr
,可以对该 xhr
监听 load
事件,并等待readyState
为 4
,status
为 200
的时候打印 xhr
的内容。
提示
readyState
为 4
且 status
为 200
通常表示请求完毕并且响应正常
这里我们打印的是 xhr.responseURL
,当然你也可以直接打印 xhr
,然后查看需要查看哪些属性。
接下来我们来看 addXMLRequestCallback
的实现
//判断XMLHttpRequest对象下是否存在回调列表,存在就push一个回调的函数
if (XMLHttpRequest.callbacks) {
XMLHttpRequest.callbacks.push(callback);
} else {
//如果不存在则在xmlhttprequest函数下创建一个回调列表
//这部分代码只会执行一次,因为创建callbacks后,上面的if会为真,然后将函数push进callbacks。
XMLHttpRequest.callbacks = [callback];
oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
//循环回调xml内的回调函数
for (i = 0; i < XMLHttpRequest.callbacks.length; i++) {
XMLHttpRequest.callbacks[i](this);
}
//由于我们复写了send函数,所以当我们在调用原send的函数的时候,需要对其传入this引用
//而arguments是传入的参数列表,我们可以在这里实现一些提交参数的修改
return oldSend.apply(this, arguments);
};
}
那么我们到这里就学会了内容监听,接下来我们看看如何进行提交劫持
提交劫持
首先我们看一下 xhr
的例子
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest();
// 2. 调用 open 函数
xhr.open("POST", "http://www.xxx.com");
// 3. 调用 send 函数
xhr.send("a=1&b=2");
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取服务器响应的数据
console.log(xhr.responseText);
}
};
可以看到发送数据主要在 send
中,我们应该主要对 send
进行劫持。
那么我们可以写出 hook
代码。
oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function (...args) {
console.log("获取到了函数", args); //此处进行劫持
return oldSend.call(this, ...args);
};
如何在 send 中对 url 进行判断
在上方的例子中我们可以知道在 open
中传入的 url
地址,而在 send
中发送数据
我们如果在 send
中想要获取 url
地址的话,使用 this
来查看 xhr
实例是找不到地址的
这个时候我们可以对 open
也进行劫持,将数据挂载到 xhr
实例上,然后再在 send
的时候进行读取
let oldOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function (method, url, async, user, password) {
this._url = url;
return oldOpen.call(this, method, url, async, user, password);
};
let oldSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
console.log("url", this._url);
return oldSend.apply(this, arguments);
};