【问题标题】:Override/Intercept XMLHttpRequest response in all browsers在所有浏览器中覆盖/拦截 XMLHttpRequest 响应
【发布时间】:2018-05-15 14:27:33
【问题描述】:

我想达到什么目的?

我想拦截 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:在严格模式下不允许分配给只读属性”。

有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: xmlhttprequest internet-explorer-11 interceptor


    【解决方案1】:

    我可以用另一种方式来做,即让一个虚拟的 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);
          }
        }
    
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-11
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    相关资源
    最近更新 更多