Chrome插件捕获异步请求与响应
由于webRequest API只能捕获请求但无法捕获响应,因此此处使用注入脚本(injected)的方式来实现。
一、测试页面
测试使用的Html代码如下,其中点击Ajax按钮将会以XMLHttpRequest方式发送Post请求,点击Fetch按钮将以fetch方式发送Get请求。
demo.html:
<!DOCTYPE HTML>
<html>
<head>
<title>demo</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<button id="ajax">Ajax</button>
<button id="fetch">Fetch</button>
<script>
$(function(){
$("#ajax").click(function(){
$.post("http://httpbin.org/post", {'hello': 'world'}, function(data){
console.log(data);
});
});
$("#fetch").click(function(){
fetch('https://jsonplaceholder.typicode.com/users/1', {'foo': 'bar'}).then(function(response){
return response.json();
}).then(function(json){
console.log(json);
});
});
});
</script>
</body>
</html>
二、Chrome插件
插件目录如下:
demo
| demo.png
| manifest.json
|
\---js
demo.js
injected.js
1、Mainifest文件
manifest.json:
{
"name": "demo",
"description" : "capture request and response",
"version": "1.0",
"manifest_version": 2,
"permissions": [
"http://*/*",
"https://*/*",
"tabs"
],
"background": {
"scripts": []
},
"content_scripts": [{
"matches": ["https://*/*", "http://*/*"],
"run_at": "document_start",
"js": ["js/demo.js"]
}],
"browser_action": {
"default_icon": "demo.png"
},
"web_accessible_resources": ["js/injected.js"]
}
其中内容脚本demo.js
中将动态加载injected.js
,由于安全原因,需要加载(注入)的js文件需要在web_accessible_resources
中配置。
2、内容脚本
demo.js:
var s = document.createElement('script');
s.src = chrome.extension.getURL('js/injected.js');
s.onload = function() {
this.remove();
};
(document.head || document.documentElement).appendChild(s);
3、注入脚本
在注入脚本中将对原生的XMLHttpRequest及fetch对象做扩展来实现对请求和响应的捕获。
injected.js:
var datas = [];
(function(xhr) {
var XHR = XMLHttpRequest.prototype;
var open = XHR.open;
var send = XHR.send;
var setRequestHeader = XHR.setRequestHeader;
XHR.open = function(method, url) {
this._method = method;
this._url = url;
this._requestHeaders = {};
this._startTime = (new Date()).toISOString();
return open.apply(this, arguments);
};
XHR.setRequestHeader = function(header, value) {
this._requestHeaders[header] = value;
return setRequestHeader.apply(this, arguments);
};
XHR.send = function(postData) {
this.addEventListener('load', function() {
var endTime = (new Date()).toISOString();
var myUrl = this._url ? this._url.toLowerCase() : this._url;
if(myUrl) {
console.log('url: ', myUrl);
console.log('postData: ', postData);
if ( this.responseType != 'blob' && this.responseText) {
try {
var text = this.responseText;
console.log('response: ', text);
} catch(err) {
console.log("Error in responseType try catch");
console.log(err);
}
}
}
});
return send.apply(this, arguments);
};
})(XMLHttpRequest);
var originalFetch = window.fetch;
window.fetch = function(url, options) {
var fch = originalFetch(url, options);
console.log('url: ', url);
console.log('options: ', options);
fch.then(function(data) {
if (data.ok && data.status == 200) {
return data.clone().json();
}
}).then(function(a){
console.log('response: ', a);
});
return fch;
}
三、效果演示
点击Ajax按钮:
点击Fetch按钮:
参考资料:
-
How we captured AJAX requests from a website tab with a Chrome Extension
-
javascript - Chrome Extension - How to get HTTP Response Body? - Stack Overflow
-
javascript - Chrome extension: intercept HTTP Response - Stack Overflow
-
javascript - Insert code into the page context using a content script - Stack Overflow