【问题标题】:Intercept XMLHttpRequest and modify responseText拦截 XMLHttpRequest 并修改 responseText
【发布时间】:2013-06-02 07:12:19
【问题描述】:

我正在尝试构建一个脚本,它将充当本机 XMLHttpRequest 对象的代理/包装器,使我能够拦截它、修改 responseText 并返回到原始的 onreadystatechange 事件。

上下文是,如果应用程序尝试接收的数据已经在本地存储中可用,则中止XMLHttpRequest 并将本地存储的数据传递回应用程序的成功/失败回调方法。假设我无法控制应用程序现有的 AJAX 回调方法。

我最初尝试了以下想法..

var send = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.send = function(data){
   //Do some stuff in here to modify the responseText
   send.call(this, data);
};

但正如我现在所建立的,responseText 是只读的。

然后我尝试退后一步,将我自己的完整本机代理写入XMLHttpRequest,最终编写了我自己的本机方法版本。类似于这里讨论的...

http://www.ilinsky.com/articles/XMLHttpRequest/#implementation-wrapping

但它很快变得混乱,并且仍然难以将修改后的数据返回到原始的onReadyStateChange方法。

有什么建议吗?这甚至可能吗?

【问题讨论】:

    标签: javascript ajax xmlhttprequest


    【解决方案1】:

    //
    // firefox, ie8+ 
    //
    var accessor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText');
    
    Object.defineProperty(XMLHttpRequest.prototype, 'responseText', {
    	get: function() {
    		console.log('get responseText');
    		return accessor.get.call(this);
    	},
    	set: function(str) {
    		console.log('set responseText: %s', str);
    		//return accessor.set.call(this, str);
    	},
    	configurable: true
    });
    
    
    //
    // chrome, safari (accessor == null)
    //
    var rawOpen = XMLHttpRequest.prototype.open;
    
    XMLHttpRequest.prototype.open = function() {
    	if (!this._hooked) {
    		this._hooked = true;
    		setupHook(this);
    	}
    	rawOpen.apply(this, arguments);
    }
    
    function setupHook(xhr) {
    	function getter() {
    		console.log('get responseText');
    
    		delete xhr.responseText;
    		var ret = xhr.responseText;
    		setup();
    		return ret;
    	}
    
    	function setter(str) {
    		console.log('set responseText: %s', str);
    	}
    
    	function setup() {
    		Object.defineProperty(xhr, 'responseText', {
    			get: getter,
    			set: setter,
    			configurable: true
    		});
    	}
    	setup();
    }

    【讨论】:

    • 这对于我需要的东西来说太过分了,但对我来说关键的收获是 var rawOpen = XMLHttpRequest.prototype.open;rawOpen.apply(this, arguments);,这让我可以插入我自己的覆盖(如你所示)但仍然让电话正常传递,以便调用者不知道任何不同。
    • 不明白你为什么先delete xhr.responseText然后var ret = xhr.responseText
    【解决方案2】:

    以下脚本在通过 XMLHttpRequest.prototype.send 发送之前完美拦截数据

    <script>
    (function(send) { 
    
            XMLHttpRequest.prototype.send = function(data) { 
    
                this.addEventListener('readystatechange', function() { 
    
                }, false); 
    
                console.log(data); 
                alert(data); 
    
            }; 
    
    })(XMLHttpRequest.prototype.send);
    </script>
    

    【讨论】:

    【解决方案3】:

    你的退步有点过头了:你可以在 XMLHttpRequest 上添加自己的 getter:(more about properties)

    Object.defineProperty(XMLHttpRequest.prototype,"myResponse",{
      get: function() {
        return this.responseText+"my update"; // anything you want
      }
    });
    

    用法:

    var xhr = new XMLHttpRequest();
    ...
    console.log(xhr.myResponse); // xhr.responseText+"my update"
    

    注意在现代浏览器上您可以运行xhr.onload(参见XMLHttpRequest2 tips

    【讨论】:

    • 谢谢。我尝试过使用这个想法,但我需要更改 xhr.responseText。通过添加新值“myResponse”,意味着必须将 onReadyStateChange 事件中的应用代码更改为使用 .myResponse 而不是 .responseText。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-26
    • 1970-01-01
    • 2020-12-12
    • 1970-01-01
    • 2014-02-04
    相关资源
    最近更新 更多