为页面上的所有 AJAX 请求添加“钩子”
Posted
技术标签:
【中文标题】为页面上的所有 AJAX 请求添加“钩子”【英文标题】:Add a "hook" to all AJAX requests on a page 【发布时间】:2011-07-09 07:21:57 【问题描述】:我想知道是否可以“挂钩”到每一个 AJAX 请求(无论是即将发送,还是在事件上)并执行操作。此时我假设页面上还有其他第三方脚本。其中一些可能使用 jQuery,而另一些则不使用。这可能吗?
【问题讨论】:
使用 jQuery 是可能的,所以使用普通的旧 javascript 也是可能的,但每个人都需要至少有 2 个“钩子”。无论如何,为什么要在同一页面上使用两者? 使用这个库怎么样? github.com/slorber/ajax-interceptor 这是一个不错的解决方案:***.com/questions/25335648/… 注意:这个问题的答案不包括在现代浏览器中使用较新的fetch()
API 进行的 Ajax 调用。
@nirvana-msu - 也许是这个:github.com/werk85/fetch-intercept/blob/develop/src/index.js
【参考方案1】:
注意:接受的答案不会产生实际响应,因为它被调用得太早了。
您可以这样做,这将在全局范围内拦截任何 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
(注意这不起作用
【讨论】:
谢谢!那是完美的。我只修改了一点:this.status
在这种情况下返回服务器状态200
如果请求正常,则返回 404 如果未找到元素,返回 500 等。但是代码,完美运行。
这可能会让你觉得老了,但你应该得到所有的爱。我被深深地困住了。非常感谢。
只是因为我已经搜索了一下。 "load"
事件仅在成功时调用。如果您不关心结果(只是查询确实结束了),您可以使用"loadend"
事件
花了很多天才找到这个。谢谢你的这个天才。
我已经尝试了很多答案,这与 WKWebView 完美配合。我在使用 Ajax 事件时遇到了麻烦,因为在调用 evaluateJavascript 或使用 addUserScript 之前可能无法加载 jQuery。谢谢!【参考方案2】:
受 aviv's answer 的启发,我做了一些调查,这就是我想出的。我不确定它是否有用,根据脚本中的 cmets当然只适用于使用原生 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
);
【讨论】:
最好扩展这个响应以支持请求后挂钩 根据您的实现,我在 NPM 上发布了一些适用于请求和响应的内容! github.com/slorber/ajax-interceptor console.log( xhr.responseText ) 是一个空字符串,因为此时 xhr 为空。如果您将 xhr 变量传递给全局变量并设置延迟几秒钟,您将能够直接访问属性 不错的答案。如果要获取响应数据,请检查状态变化时的 readyState 和状态。 xhr.onreadystatechange=function() if ( xhr.readyState == 4 && xhr.status == 200 ) console.log(JSON.parse(xhr.responseText)); @ucheng 如果我们加上xhr的onreadystatechange,会不会覆盖原来的ready状态改变方法更好用xhrObj.addEventListener("load", fn)【参考方案3】:既然你提到了 jquery,我知道 jquery 提供了一个 .ajaxSetup()
方法来设置全局 ajax 选项,其中包括像 success
、error
和 beforeSend
这样的事件触发器 - 这听起来像你正在寻找的为。
$.ajaxSetup(
beforeSend: function()
//do stuff before request fires
);
当然,您需要在尝试使用此解决方案的任何页面上验证 jQuery 可用性。
【讨论】:
感谢您的建议,但不幸的是,这不会拦截未使用 AJAX 的 AJAX 调用。 今日新闻:独角兽被不使用 AJAX 的 AJAX 调用杀死 他的意思不是 jquery AJAX 对象。但即便如此,你还是会每次都使用相同的 jquery 实例 非常有帮助。想补充一下,另一个触发器是statusCode。通过插入诸如 statusCode: 403: function() error msg 之类的内容,您可以为所有 ajax 函数提供全局 auth/perms/role 检查,而无需重新编写单个 .ajax 请求。【参考方案4】:我在 Github 上找到了一个很好的库,它做得很好,你必须在任何其他 js 文件之前包含它
https://github.com/jpillora/xhook
这是一个将 http 标头添加到任何传入响应的示例
xhook.after(function(request, response)
response.headers['Foo'] = 'Bar';
);
【讨论】:
太棒了!但是即使使用了人行横道最新的 chrome web-view 插件,也无法在 Cordova 应用程序上工作! 这非常适合我的特殊需求:在 Wordpress 中,从 Events Organizer 插件完整日历中过滤事件 不适用于所有请求,一些 fetch 和 xhr ok,但例如它不能从 google recaptcha 捕获 xhr @SergioQuintero:我认为这是您的 GitHub 问题:github.com/jpillora/xhook/issues/102。考虑在此处删除您的评论,因为这不是图书馆的问题。 @SergioQuintero 任何 XHR 接口的覆盖只发生在该文档中,而不是全局发生在浏览器中,因为这将是一个巨大的安全/隐私漏洞。 reCAPTCHA 在 iframe 中运行,您无法在其中运行覆盖。【参考方案5】:有一个诀窍。
在所有脚本运行之前,获取原始 XHMHttpReuqest 对象并将其保存在不同的 var 中。然后覆盖原始 XMLHttpRequest 并通过您自己的对象将所有调用定向到它。
伪代码:
var savd = XMLHttpRequest;
XMLHttpRequest.prototype = function()
this.init = function()
; // your code
etc' etc'
;
【讨论】:
这个答案不太对,如果你改变一个对象的原型,即使保存的原型也会改变。整个原型也被替换为一个会破坏所有 ajax 请求的函数。不过,它确实激发了我提供答案。【参考方案6】:使用“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 );
);
【讨论】:
【参考方案7】:除了 meouw 的答案之外,我还必须将代码注入到拦截 XHR 调用的 iframe 中,并使用上述答案。但是,我不得不改变
XMLHttpRequest.prototype.send = function()
收件人:
XMLHttpRequest.prototype.send = function(body)
我不得不改变
oldSend.apply(this, arguments);
收件人:
oldSend.call(this, body);
这是让它在具有IE8 文档模式的 IE9 中工作的必要条件。如果不进行此修改,则组件框架(Visual WebGUI)生成的某些回调不起作用。这些链接的更多信息:
Function.prototype.call Function.prototype.apply如果没有这些修改,AJAX 回发不会终止。
【讨论】:
【参考方案8】:jquery...
<script>
$(document).ajaxSuccess(
function(event, xhr, settings)
alert(xhr.responseText);
);
</script>
【讨论】:
jQuery 不会捕获使用其他库发出的请求。例如 ExtJS。如果您只使用 jQuery,这是一个很好的答案。否则,它不会一直有效。 如果 jquery 实例不同,它甚至不会捕获 jquery 请求。根据需要更改原型以上是关于为页面上的所有 AJAX 请求添加“钩子”的主要内容,如果未能解决你的问题,请参考以下文章