在Safari扩展程序中编写与Chrome的onBeforeRequest等效的内容

Dan*_*erz 6 safari ajax google-chrome google-chrome-extension safari-extension

Chrome扩展程序可以拦截使用指定网址的所有网络请求chrome.webRequest.onBeforeRequest.这不仅包括静态资产请求,还包括对AJAX,PJAX,favicons以及介于两者之间的所有内容的请求.

Apple提供了一些近似功能,例如beforeLoad(处理图像,CSS和JS)和beforeNavigate(处理整页加载)事件处理程序,但都没有捕获AJAX请求.我试图重载XMLHttpRequest以试图捕获AJAX加载无效(我可能做错了).这是我如何做到这一点的简短例子:

var originalOpen = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function(method, url, async, username, password) {
    console.log("overriden");
    return originalOpen.apply(this, arguments);
}
Run Code Online (Sandbox Code Playgroud)

如何在Safari扩展中捕获所有Web请求(AJAX,CSS,JS等)?

qde*_*dev 4

更新:您可以在我为 TimeCamp 跟踪器编写的第一个 Safari 扩展上检查整个代码流程: https: //github.com/qdevro/timecamp.safariextz

我已经成功拦截了所有 AJAX 调用(实际上这些响应对我来说很有趣,因为所有的魔法都发生了),但不幸的是我(还)找不到将其发送回我注入的脚本的解决方案(我仍在研究这个)现在完全正常工作 - 将 xhr 获取到注入的脚本:

我是这样做的:

1)在注入的 START 脚本上,我在 DOM 中添加了另一个脚本(执行拦截的脚本):

    $(document).ready(function(){
      var script = document.createElement('script');
      script.type = 'text/javascript';
      script.src = safari.extension.baseURI + 'path/to/your/script/bellow.js';
      document.getElementsByTagName('head')[0].appendChild(script);
    })
Run Code Online (Sandbox Code Playgroud)

2) 拦截代码使用此存储库作为 XMLHttpRequest 对象的覆盖,我也对其进行了一些调整,以便将方法、url 和发送的数据附加到它,以便在响应返回时可以轻松使用。

基本上,我已经重写了 的open()方法来XMLHttpsRequest附加我的脚本中可能需要的那些值,并在该方法中添加了 sentData send()

    var RealXHROpen = XMLHttpRequest.prototype.open;
    ...
    // Override open method of all XHR requests (inside wire() method
    XMLHttpRequest.prototype.open = function(method, url, async, user, pass) {
      this.method = method;
      this.url = url;

       RealXHROpen.apply(this, arguments);
    }
    ...
    // Override send method of all XHR requests
    XMLHttpRequest.prototype.send = function(sentData) {
       ...
       this.sentData = sentData;
       ...
    }
Run Code Online (Sandbox Code Playgroud)

然后,我在响应上添加了一个回调,当数据返回时,它会得到一个修改后的 XMLHttpRequest 对象,并包含所有内容:url、方法、sentData 和 responseText 以及检索到的数据:

    AjaxInterceptor.addResponseCallback(function(xhr) {
      console.debug("response",xhr);
      // xhr.method - contains the method used by the call
      // xhr.url - contains the URL was sent to
      // xhr.sentData - contains all the sent data (if any)
      // xhr.responseText - contains the data sent back to the request

      // Send XHR object back to injected script using DOM events
      var event = new CustomEvent("ajaxResponse", {
        detail: xhr
      });

      window.dispatchEvent(event);
    });

    AjaxInterceptor.wire();
Run Code Online (Sandbox Code Playgroud)

为了将 XHR 对象从拦截脚本发送回注入脚本,我只需使用DOM 事件,如 @Xan 建议的(感谢):

    window.addEventListener("ajaxResponse", function(evt) {
      console.debug('xhr response', evt.detail);
      // do whatever you want with the XHR details ...
    }, false);
Run Code Online (Sandbox Code Playgroud)

我在项目中使用的一些额外提示/(工作流程)优化:

  • 我已经清理了 GET url 并将所有参数 (? &) 移至 dataSent 属性中;
  • 如果有这种情况,我已经合并了这个 dataSent 属性(在方法中send(data)
  • 我在请求发送(时间戳)上添加了一个标识符,以便稍后进行匹配(请参阅下面的内容并了解想法);
  • 我已经向名为“ajaxRequest”的脚本发送了一个自定义事件,以便准备/优化加载时间(我必须使用 CORS 向某些外部 API 请求一些其他数据 - 通过将调用/响应来回传递到全局。 html 能够处理 CORS),所以我在发送 API 调用之前不必等待原始请求返回,而只需根据上面的时间戳匹配响应;