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


102

すべてのAJAXリクエストに「フック」して(送信されようとしているとき、またはイベントが発生したときに)、アクションを実行できるかどうかを知りたいです。この時点では、ページ上に他のサードパーティのスクリプトがあると想定しています。これらのいくつかはjQueryを使用するかもしれませんが、他は使用しません。これは可能ですか?


それはjQueryでも可能ですので、古いJavaScriptでも可能ですが、それぞれに少なくとも2つの「フック」が必要です。とにかく、なぜ両方を同じページで使用するのですか?
yoda

2
このライブラリを使用してどうですか?github.com/slorber/ajax-interceptor
Sebastien Lorber

これは素敵なソリューションです:stackoverflow.com/questions/25335648/...
phazei

2
注:この質問への回答は、fetch()現在のブラウザーで新しいAPI から行われたAjax呼び出しには適用されません。
jfriend00 2017年

1
@ nirvana- msu-
jfriend00

回答:


109

avivの回答に触発され、私は少し調査しましたが、これが私が思いついたものです。スクリプト内のコメント
のとおり、それがそれほど有用であるかどうかはわかりません。もちろん、ネイティブの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
});

リクエスト後のフックをサポートするようにこの応答を拡張するとよいでしょう
Sebastien Lorber 14

1
あなたの実装に基づいて、リクエストとレスポンスの両方で動作する何かをNPMに公開しました!github.com/slorber/ajax-interceptor
Sebastien Lorber

4
console.log(xhr.responseText)は、現時点ではxhrが空であるため、空の文字列です。xhr変数をグローバル変数に渡し、遅延を数秒に設定すると、プロパティに直接アクセスできるようになります
ツールキット

5
素敵な答え。応答データを取得したい場合は、readyStateと状態変化時の状態を確認してください。xhr.onreadystatechange = function(){if(xhr.readyState == 4 && xhr.status == 200){console.log(JSON.parse(xhr.responseText)); }}
スタンレーワン

1
@ucheng xhrのonreadystatechangeを追加する場合、元の準備状態の変更メソッドをオーバーライドして、xhrObj.addEventListener( "load"、fn)をより適切に使用します
Mohamed Hussain

125

注:受け入れられた回答は、あまりにも早く呼び出されるため、実際の応答をもたらしません。

あなたは一般的にインターセプトしたこれを行うことができます任意の AJAXグローバルではなく、多分任意のサードパーティの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以下では機能しないことに注意してください)


ありがとう!それは完璧に動作します。少しだけ変更しthis.statusます。この場合200、リクエストがOKの場合はサーバーのステータスを返し、要素が見つからなかった場合は404、500などを返します。ただし、コードは完全に機能します。
MrMins、2015

1
これはあなたには古く感じるかもしれませんが、あなたはこれに対するすべての愛に値します。私は深く行き詰まりました。本当にありがとう。
Carles Alcolea 2017年

これを少し検索しただけです。"load"イベントは、成功した場合に呼ばれています。結果を気にしない場合(クエリが終了しただけ)、"loadend"イベントを使用できます
Romuald Brunet

これを見つけるのに何日もかかりました。この天才の作品をありがとう。
David

私は多くの答えを試しましたが、これはWKWebViewで完全に動作します。evaluateJavascriptを呼び出すかaddUserScriptを使用する前にjQueryがロードされない可能性があるため、Ajaxイベントの使用に問題がありました。ありがとうございました!
ジェイクチェン

21

あなたはjqueryのを言及しているので、私はjqueryの申し出を知っ.ajaxSetup()セットのようなイベントのトリガーを含めグローバルなAjaxのオプションという方法をsuccesserrorbeforeSendあなたが探しているもののように聞こえるものです- 。

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

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


1
提案に感謝しますが、残念ながら、これはAJAXを使用せずに行われたAJAX呼び出しをインターセプトしません。
Yuliy

8
今日のニュース:AJAXを使用せずに行われたAJAX呼び出しによって殺されたユニコーン
Dashu

3
彼はjquery AJAXオブジェクトではないという意味です。しかし、それでもujは毎回同じjqueryインスタンスを使用します
Shishir Arora

1
とても役に立ちました。追加したい別のトリガーはstatusCodeです。statusCode:{403:function(){error msg}のようなプラグインを使用すると、単一の.ajaxリクエストを書き直すことなく、すべてのajax関数にグローバルなauth / perms / roleチェックを提供できます。
ウォーターケイマン

8

それをするトリックがあります。

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

擬似コード:

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

10
この答えは正確ではありません。オブジェクトのプロトタイプを変更すると、保存されたオブジェクトも変更されます。また、プロトタイプ全体が、すべてのajax要求を壊す1つの関数に置き換えられています。でも答えを出そうと思ったのです。
meouw

8

私はGithubでうまく機能する良いライブラリを見つけました、他のjsファイルの前にそれを含める必要があります

https://github.com/jpillora/xhook

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

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

2
偉大な者!しかし、横断歩道の最新のクロムWebビュープラグインを使用しても、Cordovaアプリケーションで動作しませんでした。
Islam Attrash 2016年

1
これは私の特定のニーズに完全に対応しました。Wordpressでは、イベントオーガナイザープラグインのフルカレンダーからのイベントのフィルタリング
Alfredo Yong

すべてのリクエストに対して機能しません。一部のフェッチとxhrは機能しますが、たとえば、google recaptchaからxhrをキャッチしません
Sergio Quintero

@SergioQuintero:私はこれがあなたのGitHubの問題であると仮定しgithub.com/jpillora/xhook/issues/102。ライブラリの問題ではなかったので、ここでコメントを削除することを検討してください。
thirtydot

@SergioQuintero XHRインターフェースのオーバーライドは、そのドキュメント内でのみ発生し、ブラウザーではグローバルに発生しません。これは、巨大なセキュリティ/プライバシーホールになるためです。reCAPTCHAはiframeで実行され、そこでオーバーライドを実行することはできません。
ウォルフ

5

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

3

jquery ...

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

1
jQueryは他のライブラリを使用して行われたリクエストをキャッチしません。たとえば、ExtJS。jQueryのみを使用している場合、それは良い答えです。それ以外の場合は、常に機能しません。
npiani 2014

1
jqueryインスタンスが異なる場合、jqueryリクエストもキャッチしません。必要に応じてプロトタイプを変更
Shishir Arora

3

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

XMLHttpRequest.prototype.send = function(){

に:

XMLHttpRequest.prototype.send = function(body)

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

oldSend.apply(this, arguments);

に:

oldSend.call(this, body);

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.