web-dev-qa-db-ja.com

ページ上のすべてのAJAXリクエストに「フック」を追加する

すべての単一のAJAXリクエストに(フックが送信されようとしているか、イベントで))「フック」してアクションを実行できるかどうかを知りたいのですが、この時点でmページに他のサードパーティスクリプトがあると仮定すると、これらの一部はjQueryを使用する場合もあれば、そうでない場合もあります。

95
Yuliy

アビブの答え に触発されて、私は少し調査しました、そして、これは私が思いついたものです。
スクリプトが有用かどうかはわかりませんスクリプトのコメントに従って、そしてもちろんネイティブXMLHttpRequestオブジェクトを使用するブラウザでのみ動作します
javascriptライブラリが使用されていれば、可能であればネイティブオブジェクトを使用するので、動作すると思います。

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

注:受け入れられた回答は、早すぎる呼び出しが行われているため、実際の応答を生成しません。

これを行うと、一般的にインターセプトするanyAJAXグローバルになり、コールバックなどを台無しにしないサードパーティによって割り当てられたAJAXライブラリ。

(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を使用してここで何ができるかについてのドキュメントがさらにあります。

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

(これはIE8以下では機能しないことに注意してください)

100
John Culviner

Jqueryについて言及しているので、jqueryはsuccesserrorbeforeSendなどのイベントトリガーを含むグローバルajaxオプションを設定する.ajaxSetup()メソッドを提供することを知っています。 -探しているもののように聞こえます。

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

もちろん、このソリューションを使用しようとするページでjQueryの可用性を確認する必要があります。

20
jondavidjohn

それを行うコツがあります。

すべてのスクリプトを実行する前に、元のXHMHttpReuqestオブジェクトを取得して別の変数に保存します。次に、元のXMLHttpRequestをオーバーライドし、独自のオブジェクトを介してすべての呼び出しを指示します。

擬似コード:

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

Githubで適切に機能するライブラリを見つけました。他のjsファイルの前に含める必要があります

https://github.com/jpillora/xhook

これは、着信応答にhttpヘッダーを追加する例です

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

「meouw」の答えを使用して、リクエストの結果を表示する場合は、次のソリューションを使用することをお勧めします

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

jquery ...

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

Meouwの答えに加えて、XHR呼び出しをインターセプトするiframeにコードを挿入する必要があり、上記の答えを使用しました。しかし、私は変更しなければなりませんでした

XMLHttpRequest.prototype.send = function(){

に:

XMLHttpRequest.prototype.send = function(arguments)

そして私は変えなければなりませんでした

oldSend.apply(this, arguments);

に:

oldSend.call(this, arguments);

これは、IE9でIE8ドキュメントモードで動作させるために必要でした。この変更が行われなかった場合、コンポーネントフレームワーク(Visual WebGUI)によって生成された一部のコールバックは機能しませんでした。これらのリンクの詳細:

これらの変更なしではAJAXポストバックは終了しませんでした。

3
WC1

Ajax-hook は、グローバルXMLHttpRequestオブジェクトをフックし、デフォルトのAjax要求と応答を変更するためのオープンソースライブラリです。 github: https://github.com/wendux/Ajax-hook 、例:

hookAjax({

  //hook callbacks
  onreadystatechange:function(xhr){
   console.log("onreadystatechange called: %O",xhr)
  },

  onload:function(xhr){
   console.log("onload called: %O",xhr)
  },

  //hook function
  open:function(arg,xhr){
   console.log("open called: method:%s,url:%s,async:%s",arg[0],arg[1],arg[2])
  }

})
1
wendu