描述
chrome.debugger
API 作为 Chrome 远程调试协议的替代传输。使用 chrome.debugger 附加到一个或多个选项卡以检测网络交互、调试 JavaScript、改变 DOM 和 CSS 等。使用 Debuggee tabId 使用 sendCommand 定位选项卡,并通过 tabId 从 onEvent 回调路由事件。
参考:live-headers
基本使用
声明权限
"permissions": [
"debugger",
],
官方demo学习
打开扩展后刷新页面,可以获取到页面都是请求了哪些数据,比如:
注: 不要点击取消或叉号,不然无法获取请求了哪些数据。
官方demo还是很简单的,有以下5个文件。我们主要学习background.js
、header.js
、
background.js
// 调试协议版本 ,这里使用 1.3. 1.3 版本是该协议的稳定 RC 版本,标记为 Chrome 64。 它包括完整协议兼容性的较小子集。
var version = "1.3";
//监听插件图标的点击
chrome.action.onClicked.addListener(function (tab) {
chrome.debugger.attach({
tabId: tab.id }, version,
// bind第一个参数传null不会改变this的执行,而且可以在后续的调用中传入参数
onAttach.bind(null, tab.id)
);
});
function onAttach(tabId) {
//判断运行期间是否产出错误
if (chrome.runtime.lastError) {
alert(chrome.runtime.lastError.message);
return;
}
//创建并打开一个新的浏览器窗口
chrome.windows.create(
{
url: "headers.html?" + tabId, type: "popup", width: 800, height: 600 }
);
}
attach方法: 将调试器附加到给定的目标。
功能: 当点击扩展图标时获取当前页面的id,并打开当前页面的的调试界面。
基于以上代码,我们也简单实现点击插件图标,弹出一个新的页面。不过需要注意manifest.json
中不要设置默认的弹出页面,不然点击图标会显示默认的弹出页面。可以只设置默认标题和默认图标
"action": {
"default_title": "Hello World",
"default_icon": "hello_extensions.png"
},
header.js
整理后
/**
* tabId
* 获取当前页面网址的请求参数
* 比如:https://www.runoob.com/try/try.php?filename=tryhtml5_video_all 获取到 filename=tryhtml5_video_all
*/
var tabId = parseInt(window.location.search.substring(1));
/**
* 给窗口添加load事件
* sendCommand:将给定的命令发送到调试目标
* 注册监听事件
*/
window.addEventListener("load", function () {
chrome.debugger.sendCommand({
tabId: tabId }, "Network.enable");
//每当调试目标发出检测事件时触发。
chrome.debugger.onEvent.addListener(onEvent);
});
/**
* 窗口关闭事件
* 窗口关闭后,断开debugger模式
*/
window.addEventListener("unload", function () {
chrome.debugger.detach({
tabId: tabId });
});
//用于保存请求的数据
var requests = {
};
/**
* 自定义的监听事件
*/
function onEvent(debuggeeId, message, params) {
if (tabId != debuggeeId.tabId)
return;
//如果将要发送请求时
if (message == "Network.requestWillBeSent") {
// 请求id,是一个字符串
var requestDiv = requests[params.requestId];
if (!requestDiv) {
// 如果对象里不存在则创建一个div,将该div放到requests对象里
var requestDiv = document.createElement("div");
requestDiv.className = "request";
requests[params.requestId] = requestDiv;
// 设置当前的请求地址
var urlLine = document.createElement("div");
urlLine.textContent = params.request.url;
requestDiv.appendChild(urlLine);
}
// 看字面意思与重定向有关
if (params.redirectResponse) {
//添加当前请求id和相应结果
appendResponse(params.requestId, params.redirectResponse);
}
// 显示请求方式、路径(相对路径),比如:GET /try/try.php?filename=tryhtml5_video_all HTTP/1.1
var requestLine = document.createElement("div");
requestLine.textContent = "\n" + params.request.method + " " +
parseURL(params.request.url).path + " HTTP/1.1";
//将请求数据最后放到div里
requestDiv.appendChild(requestLine);
document.getElementById("container").appendChild(requestDiv);
} else if (message == "Network.responseReceived") {
appendResponse(params.requestId, params.response);
}
}
// 用于添加请求
function appendResponse(requestId, response) {
var requestDiv = requests[requestId];
//添加请求头
requestDiv.appendChild(formatHeaders(response.requestHeaders));
// 显示请求状态 比如: 200 OK
var statusLine = document.createElement("div");
statusLine.textContent = "\nHTTP/1.1 " + response.status + " " +
response.statusText;
requestDiv.appendChild(statusLine);
//添加响应头
requestDiv.appendChild(formatHeaders(response.headers));
}
// 用于格式化请求头、响应头
function formatHeaders(headers) {
var text = "";
for (name in headers)
text += name + ": " + headers[name] + "\n";
var div = document.createElement("div");
div.textContent = text;
return div;
}
// 用于解析请求路径
function parseURL(url) {
var result = {
};
var match = url.match(
/^([^:]+):\/\/([^\/:]*)(?::([\d]+))?(?:(\/[^#]*)(?:#(.*))?)?$/i);
if (!match)
return result;
result.scheme = match[1].toLowerCase();
result.host = match[2];
result.port = match[3];
result.path = match[4] || "/";
result.fragment = match[5];
return result;
}