Thêm một "hook" vào tất cả các yêu cầu AJAX trên một trang


102

Tôi muốn biết liệu có thể "móc" vào mọi yêu cầu AJAX (khi nó sắp được gửi hoặc trong các sự kiện) và thực hiện một hành động hay không. Tại thời điểm này, tôi giả định rằng có các tập lệnh của bên thứ ba khác trên trang. Một số trong số này có thể sử dụng jQuery, trong khi những người khác thì không. Điều này có khả thi không?


Có thể với jQuery, vì vậy cũng có thể với javascript cũ đơn giản, nhưng bạn cần phải có ít nhất 2 "hook" cho mỗi cái. Dù sao, tại sao sử dụng cả hai trên cùng một trang?
yoda

2
Làm thế nào về việc sử dụng thư viện này? github.com/slorber/ajax-interceptor
Sebastien Lorber

Đây là một giải pháp hay: stackoverflow.com/questions/25335648/…
phazei

2
Lưu ý: Các câu trả lời cho câu hỏi này không bao gồm các lệnh gọi Ajax được thực hiện từ fetch()API mới hơn hiện nay trong các trình duyệt hiện đại.
jfriend00

Câu trả lời:


109

Lấy cảm hứng từ câu trả lời của aviv , tôi đã điều tra một chút và đây là những gì tôi đã nghĩ ra.
Tôi không chắc rằng tất cả những thứ đó hữu ích theo các nhận xét trong tập lệnh và tất nhiên sẽ chỉ hoạt động đối với các trình duyệt sử dụng đối tượng XMLHttpRequest nguyên bản .
Tôi nghĩ rằng nó sẽ hoạt động nếu các thư viện javascript được sử dụng vì chúng sẽ sử dụng đối tượng gốc nếu có thể.

function addXMLRequestCallback(callback){
    var oldSend, i;
    if( XMLHttpRequest.callbacks ) {
        // we've already overridden send() so just add the callback
        XMLHttpRequest.callbacks.push( callback );
    } else {
        // create a callback queue
        XMLHttpRequest.callbacks = [callback];
        // store the native send()
        oldSend = XMLHttpRequest.prototype.send;
        // override the native send()
        XMLHttpRequest.prototype.send = function(){
            // process the callback queue
            // the xhr instance is passed into each callback but seems pretty useless
            // you can't tell what its destination is or call abort() without an error
            // so only really good for logging that a request has happened
            // I could be wrong, I hope so...
            // EDIT: I suppose you could override the onreadystatechange handler though
            for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
                XMLHttpRequest.callbacks[i]( this );
            }
            // call the native send()
            oldSend.apply(this, arguments);
        }
    }
}

// e.g.
addXMLRequestCallback( function( xhr ) {
    console.log( xhr.responseText ); // (an empty string)
});
addXMLRequestCallback( function( xhr ) {
    console.dir( xhr ); // have a look if there is anything useful here
});

nó sẽ được tốt đẹp để mở rộng đáp ứng này để hỗ trợ móc hậu yêu cầu
Sebastien Lorber

1
Dựa trên việc triển khai của bạn, tôi đã xuất bản một số thứ trên NPM hoạt động với cả yêu cầu và phản hồi! github.com/slorber/ajax-interceptor
Sebastien Lorber

4
console.log (xhr.responseText) là một chuỗi trống vì tại thời điểm đó xhr đang trống. nếu bạn vượt qua biến XHR để biến toàn cầu và thiết lập độ trễ vài giây, bạn sẽ có thể truy cập trực tiếp các thuộc tính
Toolkit

5
câu trả lời hay. Nếu bạn muốn lấy dữ liệu phản hồi, hãy kiểm tra Trạng thái sẵn sàng và trạng thái khi trạng thái thay đổi. xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {console.log (JSON.parse (xhr.responseText)); }}
Stanley Wang

1
@ucheng Nếu chúng ta thêm onreadystatechange của XHR, nó sẽ ghi đè lên sẵn sàng ban đầu phương pháp thay đổi trạng thái tốt hơn sử dụng xhrObj.addEventListener ( "tải", fn)
Mohamed Hussain

125

LƯU Ý: Câu trả lời được chấp nhận không mang lại phản hồi thực tế vì nó được gọi quá sớm.

Bạn có thể làm điều này nói chung sẽ chặn bất kỳ AJAX nào trên toàn cầu và không làm hỏng bất kỳ lệnh gọi lại nào, v.v. có thể đã được chỉ định bởi bất kỳ thư viện AJAX nào của bên thứ ba.

(function() {
    var origOpen = XMLHttpRequest.prototype.open;
    XMLHttpRequest.prototype.open = function() {
        console.log('request started!');
        this.addEventListener('load', function() {
            console.log('request completed!');
            console.log(this.readyState); //will always be 4 (ajax is completed successfully)
            console.log(this.responseText); //whatever the response was
        });
        origOpen.apply(this, arguments);
    };
})();

Một số tài liệu khác về những gì bạn có thể làm ở đây với API addEventListener tại đây:

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Moosystem_progress

(Lưu ý điều này không hoạt động <= IE8)


Cảm ơn! Đó là hoạt động hoàn hảo. Tôi chỉ sửa đổi một chút: this.statustrả lại trạng thái máy chủ trong trường hợp này 200nếu yêu cầu là OK, 404 nếu không tìm thấy phần tử, 500, v.v. Nhưng mã, hoạt động hoàn hảo.
MrMins

1
Điều này có thể cảm thấy cũ đối với bạn nhưng bạn xứng đáng nhận được tất cả tình yêu cho điều này. Tôi đã vô cùng bế tắc. Cảm ơn nhiều.
Carles Alcolea

Đơn giản vì tôi đã tìm kiếm một chút cho điều này. Sự "load"kiện chỉ được gọi là thành công. Nếu bạn không quan tâm đến kết quả (chỉ rằng các truy vấn đã kết thúc), bạn có thể sử dụng các "loadend"sự kiện
Romuald Brunet

Phải mất nhiều ngày để tìm ra điều này. Cảm ơn bạn vì tác phẩm thiên tài này.
David

Tôi đã thử nhiều câu trả lời và điều này hoạt động hoàn hảo với WKWebView. Tôi gặp sự cố khi sử dụng các sự kiện Ajax vì jQuery có thể không được tải trước khi tôi gọi evalJavascript hoặc sử dụng addUserScript. Cảm ơn bạn!
Jake Cheng

21

Kể từ khi bạn đề cập đến jquery, tôi biết Mời jquery một .ajaxSetup()phương pháp mà sẽ đặt tùy chọn ajax toàn cầu bao gồm các kích hoạt sự kiện như success, errorbeforeSend- đó là những gì có vẻ như những gì bạn đang tìm kiếm.

$.ajaxSetup({
    beforeSend: function() {
        //do stuff before request fires
    }
});

tất nhiên, bạn sẽ cần xác minh tính khả dụng của jQuery trên bất kỳ trang nào mà bạn cố gắng sử dụng giải pháp này.


1
Cảm ơn bạn đã gợi ý, nhưng tiếc là điều này không chặn các cuộc gọi AJAX được thực hiện không sử dụng AJAX.
Yuliy

8
Trong Todays tin tức: kỳ lân bị giết bởi các cuộc gọi AJAX được thực hiện xong việc không sử dụng AJAX
Dashu

3
ý anh ấy không phải là đối tượng AJAX jquery. Nhưng thậm chí sau đó u wil hv để sử dụng cùng mọi dụ jquery
Shishir Arora

1
Vô cùng hữu ích. Muốn thêm, một trình kích hoạt khác là Mã trạng thái. Bằng cách cắm một thứ gì đó như statusCode: {403: function () {error msg}, bạn có thể cung cấp kiểm tra toàn cục auth / perms / role cho tất cả các hàm ajax mà không cần phải viết lại một yêu cầu .ajax.
Watercayman

8

Có một mẹo để làm điều đó.

Trước khi tất cả các tập lệnh chạy, hãy lấy đối tượng XHMHttpReuqest gốc và lưu nó trong một var khác. Sau đó ghi đè XMLHttpRequest gốc và hướng tất cả các lệnh gọi tới nó thông qua đối tượng của riêng bạn.

Mã psuedo:

 var savd = XMLHttpRequest;
 XMLHttpRequest.prototype = function() {
         this.init = function() {
         }; // your code
         etc' etc'
 };

10
Câu trả lời này không hoàn toàn đúng, nếu bạn thay đổi nguyên mẫu của một đối tượng thì ngay cả đối tượng đã lưu cũng sẽ bị thay đổi. Ngoài ra, toàn bộ nguyên mẫu đang được thay thế bằng một chức năng sẽ phá vỡ tất cả các yêu cầu ajax. Nó đã truyền cảm hứng cho tôi để đưa ra một câu trả lời.
meouw

8

Tôi đã tìm thấy một thư viện tốt trên Github hoạt động tốt, bạn phải đưa nó vào trước bất kỳ tệp js nào khác

https://github.com/jpillora/xhook

đây là một ví dụ thêm tiêu đề http vào bất kỳ phản hồi nào

xhook.after(function(request, response) {
  response.headers['Foo'] = 'Bar';
});

2
Tuyệt vời! Nhưng không hoạt động trên ứng dụng Cordova ngay cả với một plugin chrome xem web mới nhất dành cho người đi bộ!
Islam Attrash

1
Điều này hoạt động hoàn hảo cho các nhu cầu cụ thể của tôi: Trong Wordpress, lọc các sự kiện từ plugin Events Organizer toàn lịch
Alfredo Yong

Không hoạt động cho tất cả yêu cầu, một số tìm nạp và xhr ok, nhưng ví dụ: nó không bắt xhr từ google recaptcha
Sergio Quintero

@SergioQuintero: Tôi cho rằng đây là sự cố GitHub của bạn: github.com/jpillora/xhook/issues/102 . Hãy xem xét xóa nhận xét của bạn ở đây, vì nó không phải là vấn đề với thư viện.
ba mươi

@SergioQuintero Mọi ghi đè giao diện XHR chỉ xảy ra trong tài liệu đó, không xảy ra trên toàn cầu trong trình duyệt vì đó sẽ là một lỗ hổng bảo mật / quyền riêng tư lớn. reCAPTCHA chạy trong iframe và bạn không thể chạy ghi đè trong đó.
Walf

5

Sử dụng câu trả lời là "meouw", tôi khuyên bạn nên sử dụng giải pháp sau nếu bạn muốn xem kết quả của yêu cầu

function addXMLRequestCallback(callback) {
    var oldSend, i;
    if( XMLHttpRequest.callbacks ) {
        // we've already overridden send() so just add the callback
        XMLHttpRequest.callbacks.push( callback );
    } else {
        // create a callback queue
        XMLHttpRequest.callbacks = [callback];
        // store the native send()
        oldSend = XMLHttpRequest.prototype.send;
        // override the native send()
        XMLHttpRequest.prototype.send = function() {
            // call the native send()
            oldSend.apply(this, arguments);

            this.onreadystatechange = function ( progress ) {
               for( i = 0; i < XMLHttpRequest.callbacks.length; i++ ) {
                    XMLHttpRequest.callbacks[i]( progress );
                }
            };       
        }
    }
}

addXMLRequestCallback( function( progress ) {
    if (typeof progress.srcElement.responseText != 'undefined' &&                        progress.srcElement.responseText != '') {
        console.log( progress.srcElement.responseText.length );
    }
});

3

jquery ...

<script>
   $(document).ajaxSuccess(
        function(event, xhr, settings){ 
          alert(xhr.responseText);
        }
   );
</script>

1
jQuery sẽ không bắt các yêu cầu được thực hiện bằng các thư viện khác. Ví dụ ExtJS. Nếu bạn chỉ sử dụng jQuery, đó là một câu trả lời tốt. Nếu không, nó sẽ không hoạt động mọi lúc.
npiani

1
nó thậm chí sẽ không bắt các yêu cầu jquery nếu trường hợp jquery khác. Thay đổi trong trươc khi nếu cần thiết
Shishir Arora

3

Ngoài câu trả lời của meouw, tôi phải đưa mã vào iframe chặn các cuộc gọi XHR và sử dụng câu trả lời ở trên. Tuy nhiên, tôi đã phải thay đổi

XMLHttpRequest.prototype.send = function(){

Đến:

XMLHttpRequest.prototype.send = function(body)

Và tôi đã phải thay đổi

oldSend.apply(this, arguments);

Đến:

oldSend.call(this, body);

Điều này là cần thiết để làm cho nó hoạt động trong IE9 với chế độ tài liệu IE8 . Nếu sửa đổi này không được thực hiện, một số lệnh gọi lại được tạo bởi khung thành phần (Visual WebGUI) không hoạt động. Thông tin thêm tại các liên kết này:

Nếu không có những sửa đổi này, AJAX postbacks không chấm dứt.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.