如何使用Qt连接Headless Chrome获取XHR请求响应体(无需Fiddler)
不用Fiddler,用Qt连接Headless Chrome获取XHR响应体的方法
嘿,这个需求完全可以通过**Chrome DevTools Protocol(CDP)**来实现——Headless Chrome本身就支持通过这个协议暴露调试接口,Qt刚好能借助WebSocket和它建立通信,直接监听并抓取请求的响应体,全程不需要第三方抓包工具。下面给你一步步拆解实现思路和关键代码:
步骤1:启动开启CDP端口的Headless Chrome
首先你需要启动Headless Chrome时指定调试端口,这样Qt才能连接上它。在命令行执行:
chrome --headless=new --remote-debugging-port=9222 --disable-gpu
参数说明:
--headless=new:启用新版的无头模式(比旧版更稳定)--remote-debugging-port=9222:指定CDP的调试端口,你可以改成其他未被占用的端口--disable-gpu:禁用GPU加速,避免无头模式下的潜在问题
步骤2:用Qt获取CDP的WebSocket调试地址
Headless Chrome启动后,会在http://localhost:9222/json暴露当前所有调试目标的信息。你需要用Qt的QNetworkAccessManager请求这个接口,解析出目标页面的webSocketDebuggerUrl——这就是后续WebSocket连接的地址。
示例代码片段:
QNetworkAccessManager *manager = new QNetworkAccessManager(this); connect(manager, &QNetworkAccessManager::finished, this, [=](QNetworkReply *reply) { if (reply->error() == QNetworkReply::NoError) { QByteArray data = reply->readAll(); QJsonArray jsonArray = QJsonDocument::fromJson(data).array(); if (!jsonArray.isEmpty()) { QString wsUrl = jsonArray.first().toObject().value("webSocketDebuggerUrl").toString(); // 拿到WebSocket地址后,下一步就是建立连接 connectToCDP(wsUrl); } } reply->deleteLater(); }); manager->get(QNetworkRequest(QUrl("http://localhost:9222/json")));
步骤3:通过Qt WebSocket连接CDP并启用网络监听
拿到WebSocket地址后,用Qt的QWebSocket建立连接,连接成功后发送CDP的Network.enable命令,开启网络事件的监听。之后就能捕获所有请求的响应事件了。
示例代码:
// 可以在类中声明一个QSet来暂存待获取响应体的XHR请求ID QSet<QString> m_pendingXhrRequests; void connectToCDP(const QString &wsUrl) { QWebSocket *webSocket = new QWebSocket(); connect(webSocket, &QWebSocket::connected, this, [=]() { // 发送Network.enable命令,开启网络监听 QJsonObject enableCmd; enableCmd["id"] = 1; enableCmd["method"] = "Network.enable"; webSocket->sendTextMessage(QJsonDocument(enableCmd).toJson(QJsonDocument::Compact)); }); // 监听CDP返回的消息 connect(webSocket, &QWebSocket::textMessageReceived, this, [=](const QString &message) { QJsonObject msgObj = QJsonDocument::fromJson(message.toUtf8()).object(); // 处理Network.responseReceived事件:记录请求ID,判断是否是XHR if (msgObj.value("method").toString() == "Network.responseReceived") { QJsonObject params = msgObj.value("params").toObject(); QJsonObject response = params.value("response").toObject(); QString requestId = params.value("requestId").toString(); // 过滤XHR类型的请求 if (response.value("type").toString() == "XHR") { m_pendingXhrRequests.insert(requestId); } } // 处理Network.loadingFinished事件:触发获取响应体的命令 else if (msgObj.value("method").toString() == "Network.loadingFinished") { QString requestId = msgObj.value("params").toObject().value("requestId").toString(); if (m_pendingXhrRequests.contains(requestId)) { // 发送Network.getResponseBody命令获取响应体 QJsonObject getBodyCmd; getBodyCmd["id"] = 2; getBodyCmd["method"] = "Network.getResponseBody"; getBodyCmd["params"] = QJsonObject({{"requestId", requestId}}); webSocket->sendTextMessage(QJsonDocument(getBodyCmd).toJson(QJsonDocument::Compact)); m_pendingXhrRequests.remove(requestId); } } // 处理Network.getResponseBody的返回结果 else if (msgObj.value("id").toInt() == 2) { QJsonObject result = msgObj.value("result").toObject(); QString body = result.value("body").toString(); bool isBase64 = result.value("base64Encoded").toBool(); if (isBase64) { // 如果是base64编码,解码成原始内容 body = QString::fromUtf8(QByteArray::fromBase64(body.toUtf8())); } // 这里就是你要的XHR响应体了,可以做后续处理 qDebug() << "XHR Response Body:" << body; } }); webSocket->open(QUrl(wsUrl)); }
注意事项
- 确保你的Qt项目已经添加了WebSocket模块,在
.pro文件中加上QT += websockets - CDP的命令和事件可以参考官方的API列表,比如你还可以过滤特定URL的请求,或者监听请求发送事件
- 处理响应体时要注意编码,如果
base64Encoded为true,一定要先解码再使用 - 记得在程序退出时关闭WebSocket连接,避免资源泄漏
内容的提问来源于stack exchange,提问作者Семен Сырцов
相关产品推荐
相关产品推荐

