Tambahkan "hook" ke semua permintaan AJAX di halaman


102

Saya ingin tahu apakah mungkin untuk "menghubungkan" ke setiap permintaan AJAX (baik saat akan dikirim, atau pada acara) dan melakukan tindakan. Pada titik ini saya berasumsi bahwa ada skrip pihak ketiga lainnya di halaman. Beberapa di antaranya mungkin menggunakan jQuery, sementara yang lain tidak. Apakah ini mungkin?


Ini dimungkinkan dengan jQuery, jadi mungkin dengan javascript lama biasa, tetapi Anda harus memiliki setidaknya 2 "kait" untuk masing-masing. Bagaimanapun, mengapa menggunakan keduanya pada halaman yang sama?
yoda

2
Bagaimana kalau menggunakan perpustakaan ini? github.com/slorber/ajax-interceptor
Sebastien Lorber

Ini adalah solusi yang bagus: stackoverflow.com/questions/25335648/…
phazei

2
Catatan: Jawaban atas pertanyaan ini tidak mencakup panggilan Ajax yang dibuat dari fetch()API yang lebih baru sekarang di browser modern.
jfriend00

Jawaban:


109

Terinspirasi oleh jawaban aviv , saya melakukan sedikit penyelidikan dan inilah yang saya temukan.
Saya tidak yakin bahwa itu semua berguna sesuai dengan komentar di skrip dan tentu saja hanya akan berfungsi untuk browser yang menggunakan objek XMLHttpRequest asli .
Saya pikir itu akan berfungsi jika perpustakaan javascript digunakan karena mereka akan menggunakan objek asli jika memungkinkan.

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
});

akan menyenangkan untuk memperluas tanggapan ini untuk mendukung kait pasca-permintaan
Sebastien Lorber

1
Berdasarkan penerapan Anda, saya telah menerbitkan sesuatu di NPM yang berfungsi dengan permintaan dan tanggapan! github.com/slorber/ajax-interceptor
Sebastien Lorber

4
console.log (xhr.responseText) adalah string kosong karena pada saat itu xhr kosong. jika Anda meneruskan variabel xhr ke variabel global dan menyetel penundaan beberapa detik, Anda akan dapat mengakses properti secara langsung
Toolkit

5
jawaban bagus. Jika Anda ingin mendapatkan data respons, periksa readyState dan status ketika status berubah. xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {console.log (JSON.parse (xhr.responseText)); }}
Stanley Wang

1
@ucheng Jika kita menambahkan satureadystatechange dari xhr, apakah itu akan menimpa metode perubahan status siap asli lebih baik gunakan xhrObj.addEventListener ("load", fn)
Mohamed Hussain

125

CATATAN: Jawaban yang diterima tidak menghasilkan respons yang sebenarnya karena dipanggil terlalu dini.

Anda dapat melakukan ini yang secara umum akan mencegat AJAX apa pun secara global dan tidak mengacaukan callback apa pun, dll. Yang mungkin telah ditetapkan oleh pustaka AJAX pihak ketiga.

(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);
    };
})();

Beberapa dokumen lagi tentang apa yang dapat Anda lakukan di sini dengan addEventListener API di sini:

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

(Perhatikan ini tidak berfungsi <= IE8)


Terima kasih! Itu bekerja dengan sempurna. Saya hanya memodifikasi sedikit: this.statuskembalikan status server dalam hal ini 200jika permintaan OK, 404 jika elemen tidak ditemukan, 500, dll. Tetapi kodenya, bekerja dengan sempurna.
MrMins

1
Ini mungkin terasa tua bagi Anda, tetapi Anda pantas mendapatkan semua cinta untuk ini. Saya sangat terjebak. Terima kasih banyak.
Carles Alcolea

Hanya karena saya sudah mencari sedikit untuk ini. The "load"event hanya disebut pada keberhasilan. Jika Anda tidak peduli dengan hasilnya (hanya kueri yang berakhir), Anda dapat menggunakan "loadend"acara
Romuald Brunet

Butuh beberapa hari untuk menemukan ini. Terima kasih untuk kejeniusan ini.
David

Saya sudah mencoba banyak jawaban dan ini berfungsi sempurna dengan WKWebView. Saya mengalami masalah saat menggunakan acara Ajax karena jQuery mungkin tidak dimuat sebelum saya memanggil evaluJavascript atau menggunakan addUserScript. Terima kasih!
Jake Cheng

21

Karena Anda menyebutkan jquery, saya tahu penawaran jquery sebuah .ajaxSetup()metode yang set global yang pilihan ajax yang mencakup pemicu peristiwa seperti success, error, dan beforeSend- yang adalah apa yang terdengar seperti apa yang Anda cari.

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

tentu saja Anda perlu memverifikasi ketersediaan jQuery di halaman mana pun tempat Anda mencoba menggunakan solusi ini.


1
Terima kasih atas sarannya, tapi sayangnya ini tidak menghalangi panggilan AJAX yang dilakukan tidak menggunakan AJAX.
Yuliy

8
Dalam berita Hari Ini: Unicorn terbunuh oleh panggilan AJAX yang dilakukan tidak menggunakan AJAX
Dashu

3
maksudnya bukan objek AJAX. Tetapi bahkan kemudian Anda akan harus menggunakan contoh jquery yang sama setiap saat
Shishir Arora

1
Sangat membantu. Ingin menambahkan, pemicu lain adalah statusCode. Dengan memasukkan sesuatu seperti statusCode: {403: function () {error msg} Anda dapat memberikan pemeriksaan auth / perms / role global ke semua fungsi ajax tanpa harus menulis ulang permintaan .ajax tunggal.
Watercayman

8

Ada trik untuk melakukannya.

Sebelum semua skrip berjalan, ambil objek XHMHttpReuqest asli dan simpan di var yang berbeda. Kemudian timpa XMLHttpRequest asli dan arahkan semua panggilan ke sana melalui objek Anda sendiri.

Kode Psuedo:

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

10
Jawaban ini kurang tepat, jika Anda mengubah prototipe suatu objek bahkan yang disimpan akan berubah. Juga seluruh prototipe diganti dengan satu fungsi yang akan merusak semua permintaan ajax. Itu menginspirasi saya untuk menawarkan jawaban.
meouw

8

Saya telah menemukan perpustakaan yang bagus di Github yang melakukan pekerjaan dengan baik, Anda harus memasukkannya sebelum file js lainnya

https://github.com/jpillora/xhook

berikut adalah contoh yang menambahkan tajuk http ke setiap respons yang masuk

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

2
Bagus! Tetapi tidak berfungsi pada aplikasi Cordova bahkan dengan plugin tampilan web chrome penyeberangan terbaru!
Islam Attrash

1
Ini bekerja dengan sempurna untuk kebutuhan khusus saya: Di Wordpress, memfilter acara dari kalender lengkap plugin Penyelenggara Acara
Alfredo Yong

Tidak berfungsi untuk semua permintaan, beberapa ambil dan xhr ok, tetapi misalnya tidak menangkap xhr dari google recaptcha
Sergio Quintero

@SergioQuintero: Saya menganggap ini adalah masalah GitHub Anda: github.com/jpillora/xhook/issues/102 . Pertimbangkan untuk menghapus komentar Anda di sini, karena itu bukan masalah perpustakaan.
tigapuluhdot

@SergioQuintero Setiap penggantian antarmuka XHR hanya terjadi di dokumen itu, tidak secara global di browser karena itu akan menjadi lubang keamanan / privasi yang sangat besar. reCAPTCHA berjalan di iframe dan Anda tidak dapat menjalankan penggantian di sana.
Walf

5

Menggunakan jawaban "meouw" saya sarankan untuk menggunakan solusi berikut jika Anda ingin melihat hasil permintaan

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 tidak akan menangkap permintaan yang dibuat menggunakan pustaka lain. Misalnya ExtJS. Jika Anda hanya menggunakan jQuery, itu jawaban yang bagus. Jika tidak, itu tidak akan bekerja sepanjang waktu.
npiani

1
itu bahkan tidak akan menangkap permintaan jquery jika contoh jquery berbeda. Ubah protipe jika diperlukan
Shishir Arora

3

Selain jawaban meouw, saya harus menyuntikkan kode ke dalam iframe yang mencegat panggilan XHR, dan menggunakan jawaban di atas. Namun, saya harus berubah

XMLHttpRequest.prototype.send = function(){

Untuk:

XMLHttpRequest.prototype.send = function(body)

Dan saya harus berubah

oldSend.apply(this, arguments);

Untuk:

oldSend.call(this, body);

Ini diperlukan untuk membuatnya berfungsi di IE9 dengan mode dokumen IE8 . Jika modifikasi ini tidak dibuat, beberapa panggilan balik yang dibuat oleh kerangka komponen (Visual WebGUI) tidak bekerja. Info lebih lanjut di tautan ini:

Tanpa modifikasi ini postback AJAX tidak berhenti.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.