Bir sayfadaki tüm AJAX isteklerine bir "kanca" ekleyin


104

Her bir AJAX isteğine (gönderilmek üzere veya olaylarda) "bağlanmanın" ve bir eylem gerçekleştirmenin mümkün olup olmadığını bilmek istiyorum. Bu noktada, sayfada başka üçüncü taraf komut dosyalarının da olduğunu varsayıyorum. Bunlardan bazıları jQuery kullanabilirken diğerleri kullanmaz. Mümkün mü?


Bu jQuery ile mümkündür, bu yüzden eski javascript ile mümkündür, ancak her biri için en az 2 "kancaya" ihtiyacınız olacaktır. Her neyse, neden ikisini de aynı sayfada kullanasınız?
yoda

2
Bu kitaplığı kullanmaya ne dersiniz? github.com/slorber/ajax-interceptor
Sebastien Lorber


2
Not: Bu sorunun yanıtları, fetch()artık modern tarayıcılarda yeni API'den yapılan Ajax çağrılarını kapsamaz .
jfriend00

Yanıtlar:


110

Aviv'in cevabından esinlenerek biraz araştırma yaptım ve bulduğum şey buydu. Komut dosyasındaki açıklamalara göre
bu kadar yararlı olduğundan emin değilim ve elbette yalnızca yerel bir XMLHttpRequest nesnesi kullanan tarayıcılar için çalışacaktır .
Mümkünse yerel nesneyi kullanacaklarından javascript kitaplıkları kullanılıyorsa işe yarayacağını düşünüyorum.

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

Bu yanıtı, istek sonrası kancaları desteklemek için genişletmek güzel olurdu
Sebastien Lorber

1
Uygulamanıza dayanarak, NPM hakkında hem istekler hem de yanıtlarla çalışan bir şey yayınladım! github.com/slorber/ajax-interceptor
Sebastien Lorber

4
console.log (xhr.responseText) boş bir dizedir çünkü o anda xhr boştur. xhr değişkenini global değişkene aktarırsanız ve birkaç saniye gecikme ayarlarsanız, özelliklere doğrudan erişebileceksiniz
Araç Seti

5
güzel cevap. Yanıt verilerini almak istiyorsanız, readyState'i ve durum değiştiğinde durumu kontrol edin. xhr.onreadystatechange = function () {if (xhr.readyState == 4 && xhr.status == 200) {console.log (JSON.parse (xhr.responseText)); }}
Stanley Wang

1
@ucheng xhr'in onreadystatechange değerini eklersek, orijinal hazır durum değiştirme yöntemini geçersiz kılar mı xhrObj.addEventListener ("load", fn)
Mohamed Hussain

128

NOT: Kabul edilen yanıt, çok erken çağrıldığı için gerçek yanıtı vermez.

Bunu genel olarak herhangi bir AJAX'ı genel ve herhangi bir üçüncü taraf AJAX kitaplığı tarafından atanmış olabilecek geri aramaları vb. Bozmayacak şekilde yapabilirsiniz.

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

AddEventListener API ile burada neler yapabileceğinize dair daha fazla belge burada:

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

(Bunun işe yaramadığını unutmayın <= IE8)


Teşekkürler! Bu mükemmel çalışıyor. Ben sadece biraz değiştiririm: this.statusbu durumda 200istek OK ise sunucu durumunu döndürür, öğe bulunamazsa 404, 500 vb. Ama kod mükemmel çalışır.
MrMins

1
Bu size eski gelebilir ama bunun için tüm sevgiyi hak ediyorsunuz. Derinden sıkışmıştım. Çok teşekkürler.
Carles Alcolea

Basitçe bunun için biraz araştırma yaptım. "load"Olay sadece başarısına denir. Eğer sonucu umursamıyorsanız (sadece sorgu sona "loadend"
ermişse)

Bunu bulmak günler sürdü. Bu dahi için teşekkür ederim.
David

Birçok cevap denedim ve bu WKWebView ile mükemmel çalışıyor. JQuery, evalJavascript'i çağırmadan veya addUserScript'i kullanmadan önce yüklenemeyebileceğinden Ajax olaylarını kullanmakta sorun yaşıyordum. Teşekkür ederim!
Jake Cheng

21

Eğer jquery söz beri, jquery sunuyor bir biliyorum .ajaxSetup()yöntemi böyle olay tetikleyicileri şunlardır setleri küresel ajax seçenekleri success, errorve beforeSend- Aradığınız ne gibi sesler budur.

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

Elbette bu çözümü kullanmaya çalıştığınız herhangi bir sayfada jQuery'nin kullanılabilirliğini doğrulamanız gerekir.


1
Öneriniz için teşekkürler, ancak bu maalesef AJAX kullanılmadan yapılan AJAX çağrılarını engellemiyor.
Yuliy 05

8
Bugünün haberlerinde: AJAX kullanılmadan yapılan AJAX çağrıları tarafından öldürülen tek boynuzlu atlar
Dashu

3
AJAX nesnesini jquery demek istemiyor. Ancak o zaman bile her
seferinde

1
Çok yardımcı oldu. Eklemek istedi, başka bir tetikleyici statusCode. StatusCode: {403: function () {error msg} gibi bir şey ekleyerek, tek bir .ajax isteğini yeniden yazmak zorunda kalmadan tüm ajax işlevlerine genel bir yetkilendirme / izinler / rol kontrolü sağlayabilirsiniz.
Watercayman

8

Yapmanın bir numarası var.

Tüm komut dosyaları çalışmadan önce, orijinal XHMHttpReuqest nesnesini alın ve farklı bir var. Ardından orijinal XMLHttpRequest öğesini geçersiz kılın ve tüm çağrıları kendi nesneniz aracılığıyla ona yönlendirin.

Psuedo kodu:

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

10
Bu cevap tam olarak doğru değil, eğer bir nesnenin prototipini değiştirirseniz kaydedilen bile değişecektir. Ayrıca tüm prototip, tüm ajax isteklerini bozacak tek bir işlevle değiştiriliyor. Yine de bir cevap vermem için bana ilham verdi.
meouw

8

Github'da işi iyi yapan iyi bir kitaplık buldum, diğer js dosyalarının önüne eklemelisiniz

https://github.com/jpillora/xhook

İşte gelen herhangi bir yanıta bir http başlığı ekleyen bir örnek

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

2
Muhteşem bir tane! Ancak, yaya geçidi en son krom web görünümü eklentisiyle bile Cordova uygulaması üzerinde çalışmadı!
Islam Attrash

1
Bu, özel ihtiyaçlarım için mükemmel bir şekilde çalıştı: Wordpress'te, Events Organizer eklentisinin tam takviminden etkinlikleri filtreleme
Alfredo Yong

Tüm istekler için çalışmıyor, bazı getirme ve xhr tamam, ancak örneğin google recaptcha'dan xhr'i yakalayamıyor
Sergio Quintero

@SergioQuintero: Bunun GitHub sorununuz olduğunu varsayıyorum: github.com/jpillora/xhook/issues/102 . Kitaplıkla ilgili bir sorun olmadığı için yorumunuzu buradan silmeyi düşünün.
otuz nokta

@SergioQuintero XHR arabirimlerinin herhangi bir şekilde geçersiz kılınması yalnızca bu belgede gerçekleşir, tarayıcıda değil, çünkü bu büyük bir güvenlik / gizlilik açığı olur. reCAPTCHA bir iframe içinde çalışır ve burada geçersiz kılmayı çalıştıramazsınız.
Walf

5

"Meouw" cevabını kullanarak, istek sonuçlarını görmek istiyorsanız aşağıdaki çözümü kullanmanızı öneririm.

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, diğer kitaplıklar kullanılarak yapılan istekleri yakalamaz. Örneğin ExtJS. Yalnızca jQuery kullanıyorsanız, bu iyi bir yanıttır. Aksi takdirde, her zaman işe yaramaz.
npiani

1
jquery örneği farklıysa jquery isteklerini bile yakalamaz. Gerekirse protype'ta değişiklik
Shishir Arora

3

Meouw'un cevabına ek olarak, XHR çağrılarını kesen bir iframe'e kod enjekte etmek zorunda kaldım ve yukarıdaki cevabı kullandım. Ancak değiştirmek zorunda kaldım

XMLHttpRequest.prototype.send = function(){

Kime:

XMLHttpRequest.prototype.send = function(body)

Ve değişmek zorundaydım

oldSend.apply(this, arguments);

Kime:

oldSend.call(this, body);

IE9 belge moduyla IE9'da çalışmasını sağlamak için bu gerekliydi . Bu değişiklik yapılmadıysa, bileşen çerçevesi (Visual WebGUI) tarafından oluşturulan bazı geri aramalar çalışmadı. Bu bağlantılarda daha fazla bilgi:

Bu değişiklikler olmadan AJAX geri gönderimleri sona ermedi.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.