You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让基于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 05:28:10