如何拦截不同JS库发出的所有AJAX请求

IT技术 javascript ajax interceptor
2021-01-30 12:48:47

我正在使用不同的 JS 库(AngularJS、OpenLayers 等)构建一个 Web 应用程序,并且需要一种方法来拦截所有 AJAX 响应,以便在登录的用户会话过期(响应返回401 Unauthorized状态)的情况下重定向他到登录页面。

我知道 AngularJS 提供interceptors管理此类场景,但无法找到一种方法来实现对 OpenLayers 请求的这种注入。所以我选择了一种普通的 JS 方法。

在这里我找到了这段代码......

(function(open) {

    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {

        this.addEventListener("readystatechange", function() {
            console.log(this.readyState); // this one I changed
        }, false);

        open.call(this, method, url, async, user, pass);
    };

})(XMLHttpRequest.prototype.open);

...我对其进行了调整,看起来它的行为符合预期(仅在上一个 Google Chrome 上对其进行了测试)。

当它修改 XMLHTTPRequest 的原型时,我想知道这会导致多么危险,或者它是否会产生严重的性能问题。顺便说一句,会有任何有效的选择吗?

更新:如何在请求被发送之前拦截请求

以前的技巧工作正常。但是,如果在相同的场景中您想在发送请求之前注入一些标头怎么办?请执行下列操作:

(function(send) {

    XMLHttpRequest.prototype.send = function(data) {

        // in this case I'm injecting an access token (eg. accessToken) in the request headers before it gets sent
        if(accessToken) this.setRequestHeader('x-access-token', accessToken);

        send.call(this, data);
    };

})(XMLHttpRequest.prototype.send);
4个回答

这种类型的函数挂钩是完全安全的,并且由于其他原因在其他方法上定期执行。

而且,唯一的性能影响实际上只是每个额外的函数调用.open()以及您自己执行的任何代码,这在涉及网络调用时可能无关紧要。


在 IE 中,这不会捕获任何尝试使用ActiveXObjectAjax 控制方法的代码编写良好的代码首先查找XMLHttpRequest对象,并在可用时使用对象,并且自 IE 7 以来一直可用。但是,可能会有一些代码使用该ActiveXObject方法(如果它可用),这在 IE 的更高版本中将是正确的。


在现代浏览器中,还有其他方法可以发出 Ajax 调用,例如fetch()接口,因此如果要挂钩所有 Ajax 调用,则必须挂钩的不仅仅是XMLHttpRequest.

@bagofcole - 您大概可以修补该fetch()函数以拦截对它的所有调用 - 尽管我自己从未尝试过。看起来这个module就是这样做的。
2021-03-24 12:48:47
尝试挂钩comment_service_ajax请求时会中断 YouTube
2021-03-30 12:48:47
嗨@jfriend00 - 你将如何挂钩所有获取 api 请求 - stackoverflow.com/questions/44728723/...
2021-04-09 12:48:47

对于某些版本的 IE (9 及以下),这不会捕获 XMLHttpRequests 根据库的不同,他们可能会首先查找 IE 的专有 ActiveX 控件。

而且,当然,如果您在 IE 下使用非严格的 DOCTYPE,那么所有的赌注都会被取消,但我相信您知道这一点。

参考:CanIuse

正如 Firefox AMO Editor 所友好指出的那样Rob W

以下代码更改 XMLHttpRequest 的行为。默认情况下,如果未指定第三个(“async”)参数,则默认为 true。当它被指定和未定义时,它相当于“false”,它将一个请求变成一个同步的 HTTP 请求。这会导致 UI 在处理请求时阻塞,并且 XMLHttpRequest API 的某些功能也被禁用。

...

要解决此问题,请将 open.call(....) 替换为 open.apply(this, arguments);

这是一个参考链接:

https://xhr.spec.whatwg.org/#the-open()-method

(其中“以下代码”是指问题中的片段)
2021-04-12 12:48:47

试试这个

let oldXHROpen = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function(method, url, async, user, password) {

console.log({method});

// Show loader

 this.addEventListener('load', function() {
  console.log('load: ' + this.responseText);
  // Hide loader
 });
           
  return oldXHROpen.apply(this, arguments);
}