在 Safari 扩展中编写等同于 Chrome 的 onBeforeRequest
Writing an equivalent to Chrome's onBeforeRequest in a Safari extension
Chrome 扩展能够使用 chrome.webRequest.onBeforeRequest
拦截 所有 对指定 URL 的 Web 请求。这不仅包括静态资产请求,还包括对 AJAX、PJAX、网站图标以及介于两者之间的所有内容的请求。
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);
}
如何在 Safari 扩展程序中捕获所有 Web 请求(AJAX、CSS、JS 等)?
更新: 您可以在我为 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);
})
2) 拦截代码使用 this repository 作为 XMLHttpRequest 对象的覆盖,我也对其进行了一些调整以附加方法 url 并向其发送数据以便在响应返回时轻松可用。
基本上,我重写了 XMLHttpsRequest
的 open()
方法来附加我在脚本中可能需要的那些值,并在 send()
方法中添加了 sentData 作为嗯:
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;
...
}
然后,我在响应上添加了一个回调,当数据返回时,它会得到一个修改过的 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();
为了将 XHR 对象从拦截脚本发送回注入脚本,我只需要像@Xan 建议的那样使用 DOM events(感谢):
window.addEventListener("ajaxResponse", function(evt) {
console.debug('xhr response', evt.detail);
// do whatever you want with the XHR details ...
}, false);
我在项目中使用的一些额外提示/(工作流程)优化:
- 我已经清理了 GET url 并将所有参数 (?&) 移动到 dataSent 属性;
- 如果有的话,我已经合并了这个 dataSent 属性(在
send(data)
方法中)
- 我在请求发送时添加了一个标识符(时间戳)以便稍后匹配它(请参阅下面的点并了解想法);
- 我已经向名为 "ajaxRequest" 的脚本发送了一个自定义事件,以便准备/优化加载时间(我不得不使用 CORS 向某些外部 API 请求一些其他数据 - 通过传递来回调用/响应到能够处理 CORS 的 global.html),所以在发送我的 API 调用之前,我不必等待原始请求返回,而只是匹配基于上述时间戳的响应;
Chrome 扩展能够使用 chrome.webRequest.onBeforeRequest
拦截 所有 对指定 URL 的 Web 请求。这不仅包括静态资产请求,还包括对 AJAX、PJAX、网站图标以及介于两者之间的所有内容的请求。
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);
}
如何在 Safari 扩展程序中捕获所有 Web 请求(AJAX、CSS、JS 等)?
更新: 您可以在我为 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);
})
2) 拦截代码使用 this repository 作为 XMLHttpRequest 对象的覆盖,我也对其进行了一些调整以附加方法 url 并向其发送数据以便在响应返回时轻松可用。
基本上,我重写了 XMLHttpsRequest
的 open()
方法来附加我在脚本中可能需要的那些值,并在 send()
方法中添加了 sentData 作为嗯:
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;
...
}
然后,我在响应上添加了一个回调,当数据返回时,它会得到一个修改过的 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();
为了将 XHR 对象从拦截脚本发送回注入脚本,我只需要像@Xan 建议的那样使用 DOM events(感谢):
window.addEventListener("ajaxResponse", function(evt) {
console.debug('xhr response', evt.detail);
// do whatever you want with the XHR details ...
}, false);
我在项目中使用的一些额外提示/(工作流程)优化:
- 我已经清理了 GET url 并将所有参数 (?&) 移动到 dataSent 属性;
- 如果有的话,我已经合并了这个 dataSent 属性(在
send(data)
方法中) - 我在请求发送时添加了一个标识符(时间戳)以便稍后匹配它(请参阅下面的点并了解想法);
- 我已经向名为 "ajaxRequest" 的脚本发送了一个自定义事件,以便准备/优化加载时间(我不得不使用 CORS 向某些外部 API 请求一些其他数据 - 通过传递来回调用/响应到能够处理 CORS 的 global.html),所以在发送我的 API 调用之前,我不必等待原始请求返回,而只是匹配基于上述时间戳的响应;