如何让基于Qt实现的WebPush在Windows Edge浏览器正常工作?
Qt WebPush在Edge浏览器中400错误排查与解决
问题现象
- 基于Qt实现的WebPush在Chrome、Firefox浏览器中推送正常,但在Windows Edge浏览器中返回400错误,即使对Endpoint进行URL解码后仍无法解决
- Chrome使用FCM格式的Endpoint(如
https://fcm.googleapis.com/fcm/send/xxx),Edge使用WNS格式的Endpoint(带token查询参数,包含大量URL编码字符) - 相同的VAPID密钥、Endpoint、P256DH、AUTH参数组合,在C#的WebPush-NetCore库中可正常完成推送
- Qt端报错信息:
400: "Error transferring -server replied: "
相关代码展示
web-push.pro项目文件
QT += core network TARGET = web-push TEMPLATE = app LIBS += -lpusha -lecec SOURCES += main.cpp
main.cpp核心代码
#include <QCoreApplication> #include <QNetworkAccessManager> #include <QNetworkRequest> #include <QNetworkReply> #include <QUrl> #include <QDebug> #include "pusha.h" #include "ecec.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 推送参数配置 QString endpoint = "https://wns2-pn1p.notify.windows.com/w/?token=BQYAAACbMWA0QtGcCaM00KJntpBBrdmzSvWUnBmgRwUFnM6fJEySP1Jr0Fi3OU2rgTICDfl2Bsj6jS4eNZLo0FQK1diyqN1v6zi7k9yBijIksEvKegd2q2Z%2bGAIoIt0QfnQyluOGSNgXCrF0jr4h3Ka5aJUVdl7aBSkkULq5PI7wvGl3mGMD9I3xk71jG%2bjBAwoF2ThvYfefEEpd5xMAJ%2bWLBd3FD56kD1zTplOhwS4Leysw3SFBXh393%2b8MfDFJCAi%2f0mfKLBy%2fTCuha50GJT7oBJHemhFCi5E2CliZ9dFB2IPCpEa%2bEfgVWHC6GkpRMjUSCs0%3d"; QString p256dh = "你的P256DH值"; QString auth = "你的AUTH值"; QString vapidPublicKey = "你的VAPID公钥"; QString vapidPrivateKey = "你的VAPID私钥"; // 尝试解码Endpoint(无效) QUrl decodedEndpoint = QUrl::fromPercentEncoding(endpoint.toUtf8()); // 使用pusha库构造加密内容与请求头 Pusha pusha; pusha.setVapidKeys(vapidPublicKey.toUtf8(), vapidPrivateKey.toUtf8()); pusha.setEndpoint(decodedEndpoint.toString().toUtf8()); pusha.setP256dh(p256dh.toUtf8()); pusha.setAuth(auth.toUtf8()); QString payload = "{\"title\":\"Edge推送测试\",\"body\":\"测试内容\"}"; QByteArray encryptedPayload = pusha.encrypt(payload.toUtf8()); // 构造网络请求 QNetworkAccessManager manager; QNetworkRequest request(decodedEndpoint); request.setRawHeader("Content-Type", "application/octet-stream"); request.setRawHeader("Authorization", pusha.buildAuthorizationHeader().toUtf8()); request.setRawHeader("Crypto-Key", pusha.buildCryptoKeyHeader().toUtf8()); request.setRawHeader("TTL", "60"); // 发送请求并处理响应 QNetworkReply *reply = manager.post(request, encryptedPayload); QObject::connect(reply, &QNetworkReply::finished, [&]() { if (reply->error() != QNetworkReply::NoError) { qDebug() << "错误信息:" << reply->errorString(); qDebug() << "状态码:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); } else { qDebug() << "推送成功!"; } reply->deleteLater(); a.quit(); }); return a.exec(); }
排查方向与解决办法
1. WNS Endpoint的URL解析问题
Edge的WNS Endpoint包含大量URL编码字符,Qt的QUrl自动解析逻辑优于手动解码:
- 直接使用原始Endpoint字符串构造
QUrl,避免手动解码导致的参数丢失或格式错误:QUrl endpointUrl(endpoint); // 无需手动解码,QUrl会自动处理编码部分 - 验证token参数是否被正确解析:
qDebug() << "解析后的Token:" << endpointUrl.query().value("token");
2. WNS专属请求头配置
WNS对请求头的要求与FCM存在差异,需补充关键头信息:
- 添加
X-WNS-Type头,根据推送类型设置对应值(如wns/toast对应通知弹窗):request.setRawHeader("X-WNS-Type", "wns/toast"); - 对比WebPush-NetCore生成的
Authorization和Crypto-Key头,确保pusha库生成的格式完全一致(如VAPID签名的前缀、参数顺序)。
3. SSL协议版本要求
WNS强制要求使用TLS 1.2及以上版本,需手动配置Qt的SSL参数:
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration(); sslConfig.setProtocol(QSsl::TlsV1_2OrLater); request.setSslConfiguration(sslConfig);
4. ECE加密逻辑一致性
检查ecec库的加密逻辑是否符合Web Push规范,对比WebPush-NetCore生成的加密payload:
- 验证密钥派生算法、填充方式、IV生成逻辑是否与规范完全匹配
- 确保payload大小未超过WNS的限制(toast类型推送最大约5KB)
5. 抓包对比请求差异
使用Fiddler等工具分别抓取WebPush-NetCore和Qt端的请求,对比以下内容:
- 请求头的所有字段(包括大小写、参数细节)
- 加密后的payload内容
- 请求URL的解析结果
根据差异针对性调整Qt端的请求构造逻辑。
内容的提问来源于stack exchange,提问作者iammilind
相关产品推荐
相关产品推荐

