2013-06-06 5 views
11

Tôi đang cố tạo một tập lệnh sẽ hoạt động như một proxy/trình bao bọc cho đối tượng gốc XMLHttpRequest cho phép tôi chặn nó, sửa đổi responseText và quay lại sự kiện onreadystatechange gốc.Chặn XMLHttpRequest và sửa đổi responseText

Ngữ cảnh là, nếu dữ liệu ứng dụng đang cố gắng nhận đã có sẵn trong bộ nhớ cục bộ, để hủy bỏ số XMLHttpRequest và chuyển dữ liệu được lưu trữ cục bộ trở lại phương pháp gọi lại thành công/thất bại của ứng dụng. Giả sử tôi không kiểm soát được các phương thức gọi lại AJAX hiện có của ứng dụng.

Ban đầu tôi đã thử các ý tưởng sau đây ..

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

Nhưng bây giờ tôi đã thiết lập, responseText là chỉ đọc.

Sau đó, tôi đã thử thực hiện một bước trở lại, viết proxy riêng đầy đủ của riêng mình đến XMLHttpRequest, cuối cùng kết thúc bằng văn bản phiên bản của riêng tôi về các phương pháp gốc. Tương tự như những gì được thảo luận ở đây ...

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

Nhưng nó nhanh chóng nhận được khó hiểu, và vẫn có những khó khăn trong việc trả lại dữ liệu biến đổi trở lại vào phương pháp ban đầu onReadyStateChange.

Mọi đề xuất? Điều này thậm chí có thể?

Trả lời

5

// 
 
// firefox, ie8+ 
 
// 
 
var accessor = Object.getOwnPropertyDescriptor(XMLHttpRequest.prototype, 'responseText'); 
 

 
Object.defineProperty(XMLHttpRequest.prototype, 'responseText', { 
 
\t get: function() { 
 
\t \t console.log('get responseText'); 
 
\t \t return accessor.get.call(this); 
 
\t }, 
 
\t set: function(str) { 
 
\t \t console.log('set responseText: %s', str); 
 
\t \t //return accessor.set.call(this, str); 
 
\t }, 
 
\t configurable: true 
 
}); 
 

 

 
// 
 
// chrome, safari (accessor == null) 
 
// 
 
var rawOpen = XMLHttpRequest.prototype.open; 
 

 
XMLHttpRequest.prototype.open = function() { 
 
\t if (!this._hooked) { 
 
\t \t this._hooked = true; 
 
\t \t setupHook(this); 
 
\t } 
 
\t rawOpen.apply(this, arguments); 
 
} 
 

 
function setupHook(xhr) { 
 
\t function getter() { 
 
\t \t console.log('get responseText'); 
 

 
\t \t delete xhr.responseText; 
 
\t \t var ret = xhr.responseText; 
 
\t \t setup(); 
 
\t \t return ret; 
 
\t } 
 

 
\t function setter(str) { 
 
\t \t console.log('set responseText: %s', str); 
 
\t } 
 

 
\t function setup() { 
 
\t \t Object.defineProperty(xhr, 'responseText', { 
 
\t \t \t get: getter, 
 
\t \t \t set: setter, 
 
\t \t \t configurable: true 
 
\t \t }); 
 
\t } 
 
\t setup(); 
 
}

+0

Điều này là quá mức cần thiết cho những gì tôi cần, nhưng takeaway quan trọng đối với tôi là 'var rawOpen = XMLHttpRequest.prototype.open;' và 'rawOpen.apply (this, arguments);', cho phép tôi cắm vào ghi đè của riêng mình (khi bạn hiển thị) nhưng vẫn cho phép cuộc gọi đi qua như bình thường để người gọi không biết gì khác. –

0

bước trở lại của bạn là một overkill: bạn có thể thêm getter của riêng bạn trên XMLHttpRequest: (more about properties)

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

việc sử dụng:

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

Note trên các trình duyệt hiện đại, bạn có thể chạy xhr.onload (xem XMLHttpRequest2 tips)

+0

Cảm ơn. Tôi đã thử sử dụng ý tưởng này, nhưng tôi cần xhr.responseText để thay đổi. Bằng cách thêm giá trị mới, 'myResponse', có nghĩa là phải thay đổi mã ứng dụng trong sự kiện onReadyStateChange để sử dụng .myResponse thay vì .responseText. – james

0

Tập lệnh sau sẽ chặn hoàn toàn dữ liệu trước khi gửi qua 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>