Override/Intercept 所有浏览器中的 XMLHttpRequest 响应
Override/Intercept XMLHttpRequest response in all browsers
我想达到什么目的?
我想拦截 XMLHttpRequest 并修改某些特定请求的响应。 (例如解密内容并将其分配给返回响应)
到目前为止我做了什么?
以下代码拦截请求并修改响应。它适用于除 IE 11 之外的所有浏览器(Chrome、Firefox、Opera、Edge)。
const dummySend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
const _onreadystatechange = this.onreadystatechange;
this.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200 || this.status === 1223) {
// as response is read-only and configurable, make it writable
Object.defineProperty(this, 'response', {writable: true});
this.response = modifyResponse(this.response);
}
}
if (_onreadystatechange) {
_onreadystatechange.apply(this, arguments);
}
}
dummySend.apply(__self, arguments);
}
问题是什么?
所有这些仅在 IE 11 中不起作用,抛出的错误是 'TypeError: Assignment to read-only property is not allowed in strict mode'。
有人可以帮我解决这个问题吗?
我可以用另一种方法来做到这一点,即向原始请求者公开一个虚拟 XMLHttpRequest 对象,然后自己处理实际的 XMLHttpRequest。请阅读代码以获得更多清晰度。
let oldXMLHttpRequest = window.XMLHttpRequest;
// define constructor for XMLHttpRequest proxy object
window.XMLHttpRequest = function() {
let _originalXhr = new oldXMLHttpRequest();
let _dummyXhr = this;
function decryptResponse(actualResponse) {
return base64Decrypted = decrypt(response, secret);
}
_dummyXhr.response = null;
// expose dummy open
_dummyXhr.open = function () {
const _arguments = [].slice.call(arguments);
// do any url modifications here before request open
_dummyXhr._url = _arguments[1];
return _originalXhr.open.apply(_originalXhr, _arguments);
};
// expose dummy send
_dummyXhr.send = function () {
let _onreadystatechange = _dummyXhr.onreadystatechange;
_originalXhr.onreadystatechange = function() {
if (this.readyState === 4 && (this.status === 200 || this.status === 1223)) {
_dummyXhr.response = decryptResponse(this.response);
}
// call callback that was assigned on our object
if (_onreadystatechange) {
_onreadystatechange.apply(_dummyXhr, arguments);
}
}
_originalXhr.send.apply(_originalXhr, arguments);
};
// iterate all properties in _originalXhr to proxy them according to their type
// For functions, we call _originalXhr and return the result
// For non-functions, we make getters/setters
// If the property already exists on _dummyXhr, then don't proxy it
for (let prop in _originalXhr) {
// skip properties we already have - this will skip both the above defined properties
// that we don't want to proxy and skip properties on the prototype belonging to Object
if (!(prop in _dummyXhr)) {
// create closure to capture value of prop
(function(prop) {
if (typeof _originalXhr[prop] === "function") {
// define our own property that calls the same method on the _originalXhr
Object.defineProperty(_dummyXhr, prop, {
value: function() {return _originalXhr[prop].apply(_originalXhr, arguments);}
});
} else {
// define our own property that just gets or sets the same prop on the _originalXhr
Object.defineProperty(_dummyXhr, prop, {
get: function() {return _originalXhr[prop];},
set: function(val) {_originalXhr[prop] = val;}
});
}
})(prop);
}
}
我想达到什么目的?
我想拦截 XMLHttpRequest 并修改某些特定请求的响应。 (例如解密内容并将其分配给返回响应)
到目前为止我做了什么?
以下代码拦截请求并修改响应。它适用于除 IE 11 之外的所有浏览器(Chrome、Firefox、Opera、Edge)。
const dummySend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function () {
const _onreadystatechange = this.onreadystatechange;
this.onreadystatechange = function () {
if (this.readyState === 4) {
if (this.status === 200 || this.status === 1223) {
// as response is read-only and configurable, make it writable
Object.defineProperty(this, 'response', {writable: true});
this.response = modifyResponse(this.response);
}
}
if (_onreadystatechange) {
_onreadystatechange.apply(this, arguments);
}
}
dummySend.apply(__self, arguments);
}
问题是什么?
所有这些仅在 IE 11 中不起作用,抛出的错误是 'TypeError: Assignment to read-only property is not allowed in strict mode'。
有人可以帮我解决这个问题吗?
我可以用另一种方法来做到这一点,即向原始请求者公开一个虚拟 XMLHttpRequest 对象,然后自己处理实际的 XMLHttpRequest。请阅读代码以获得更多清晰度。
let oldXMLHttpRequest = window.XMLHttpRequest;
// define constructor for XMLHttpRequest proxy object
window.XMLHttpRequest = function() {
let _originalXhr = new oldXMLHttpRequest();
let _dummyXhr = this;
function decryptResponse(actualResponse) {
return base64Decrypted = decrypt(response, secret);
}
_dummyXhr.response = null;
// expose dummy open
_dummyXhr.open = function () {
const _arguments = [].slice.call(arguments);
// do any url modifications here before request open
_dummyXhr._url = _arguments[1];
return _originalXhr.open.apply(_originalXhr, _arguments);
};
// expose dummy send
_dummyXhr.send = function () {
let _onreadystatechange = _dummyXhr.onreadystatechange;
_originalXhr.onreadystatechange = function() {
if (this.readyState === 4 && (this.status === 200 || this.status === 1223)) {
_dummyXhr.response = decryptResponse(this.response);
}
// call callback that was assigned on our object
if (_onreadystatechange) {
_onreadystatechange.apply(_dummyXhr, arguments);
}
}
_originalXhr.send.apply(_originalXhr, arguments);
};
// iterate all properties in _originalXhr to proxy them according to their type
// For functions, we call _originalXhr and return the result
// For non-functions, we make getters/setters
// If the property already exists on _dummyXhr, then don't proxy it
for (let prop in _originalXhr) {
// skip properties we already have - this will skip both the above defined properties
// that we don't want to proxy and skip properties on the prototype belonging to Object
if (!(prop in _dummyXhr)) {
// create closure to capture value of prop
(function(prop) {
if (typeof _originalXhr[prop] === "function") {
// define our own property that calls the same method on the _originalXhr
Object.defineProperty(_dummyXhr, prop, {
value: function() {return _originalXhr[prop].apply(_originalXhr, arguments);}
});
} else {
// define our own property that just gets or sets the same prop on the _originalXhr
Object.defineProperty(_dummyXhr, prop, {
get: function() {return _originalXhr[prop];},
set: function(val) {_originalXhr[prop] = val;}
});
}
})(prop);
}
}