HTTP 客户端

演示了一个简单的 HTTP 客户端。

本示例演示了简单的 HTTP 客户端如何从远程主机获取文件。

用户在主窗口中输入网址、文件名和下载位置。QNetworkAccessManager 类利用这些信息来下载文件

本示例的主要工作由 HttpWindow 类完成,因此我们将重点关注该类。

QNetworkRequest networkRequest(url);
networkRequest.setTcpKeepAliveIdleTimeBeforeProbes(20s);
networkRequest.setTcpKeepAliveIntervalBetweenProbes(2s);
networkRequest.setTcpKeepAliveProbeCount(5);

从 Qt 6.11 开始,可以为 `QNetworkRequest` 显式指定 TCP 保持活动(keepalive)参数。在上面的代码片段中,我们覆盖了 `QNetworkAccessManager ` 使用的默认设置,以采用更积极的策略。例如,这在早期检测由 Linux 系统上的网络变化引起的网络卡死时非常有用。 在此示例中,若连接处于闲置状态三十秒,则会关闭该连接。

reply.reset(qnam.get(networkRequest));

通过QNetworkAccessManager ,我们开始下载由url 指向的资源。如果您不熟悉该类或其使用的QNetworkAccessManager::get() 函数,或者只是想更详细地了解它,请查阅其文档以及QNetworkReply 和QNetworkRequest 的文档。

    connect(reply.get(), &QNetworkReply::finished, this, &HttpWindow::httpFinished);
    connect(reply.get(), &QIODevice::readyRead, this, &HttpWindow::httpReadyRead);
#if QT_CONFIG(ssl)
    connect(reply.get(), &QNetworkReply::sslErrors, this, &HttpWindow::sslErrors);
#endif

在上文中,我们将回复的一些信号连接到了类中的槽(slot)上。这些槽将负责处理传入的数据,并完成下载操作或处理错误。

connect(reply.get(), &QIODevice::readyRead, this, &HttpWindow::httpReadyRead);

至于处理传入的数据,由于我们无法确定潜在输入的最大下载大小,且不希望耗尽可能运行该示例程序的任何计算机的内存,因此我们在QNetworkReply::readyRead()中处理传入的数据,而不是在QNetworkReply::finished()中处理。

void HttpWindow::httpReadyRead()
{
    // This slot gets called every time the QNetworkReply has new data.
    // We read all of its new data and write it into the file.
    // That way we use less RAM than when reading it at the finished()
    // signal of the QNetworkReply
    if (file)
        file->write(reply->readAll());
}

然后,我们会在数据到达时将其写入文件。虽然这种方式不太方便,但应用程序在峰值时的内存消耗会更少!

connect(reply.get(), &QNetworkReply::sslErrors, this, &HttpWindow::sslErrors);

借助QNetworkReply::sslErrors() 信号,我们还可以处理连接到安全网站(即 HTTPS)时 TLS 握手过程中可能发生的错误。

void HttpWindow::sslErrors(const QList<QSslError> &errors)
{
    QString errorString;
    for (const QSslError &error : errors) {
        if (!errorString.isEmpty())
            errorString += '\n';
        errorString += error.errorString();
    }

    if (QMessageBox::warning(this, tr("TLS Errors"),
                             tr("One or more TLS errors has occurred:\n%1").arg(errorString),
                             QMessageBox::Ignore | QMessageBox::Abort)
        == QMessageBox::Ignore) {
        reply->ignoreSslErrors();
    }
}

在此示例中,我们会向用户显示一个对话框,以便用户选择是否忽略这些错误。

QNetworkReply::NetworkError error = reply->error();
const QString &errorString = reply->errorString();
if (error != QNetworkReply::NoError) {
    QFile::remove(fi.absoluteFilePath());
    // For "request aborted" we handle the label and button in cancelDownload()
    if (!httpRequestAborted) {
        statusLabel->setText(tr("Download failed:\n%1.").arg(errorString));
        downloadButton->setEnabled(true);
    }
    return;
}

如果发生错误,QNetworkReply 将发出QNetworkReply::errorOccurred()信号,随后发出QNetworkReply::finished()信号。在此示例中,我们仅监听后者。我们在相应的槽中处理任何潜在错误,方法是删除正在写入的文件,并通过状态标签显示错误信息。

connect(&qnam, &QNetworkAccessManager::authenticationRequired,
        this, &HttpWindow::slotAuthenticationRequired);

如果您连接到一个使用HTTP 身份验证的网站,假设您事先未提供应使用的凭据,则可以在网站请求凭据时处理凭据缺失的情况。通过QNetworkAccessManager ,我们通过连接到QNetworkAccessManager::authenticationRequired() 信号的槽来实现这一点。我们仅在构造函数中建立一次此连接。

void HttpWindow::slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator)
{
    QDialog authenticationDialog;
    Ui::Dialog ui;
    ui.setupUi(&authenticationDialog);
    authenticationDialog.adjustSize();
    ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm(), url.host()));

    // Did the URL have information? Fill the UI.
    // This is only relevant if the URL-supplied credentials were wrong
    ui.userEdit->setText(url.userName());
    ui.passwordEdit->setText(url.password());

    if (authenticationDialog.exec() == QDialog::Accepted) {
        authenticator->setUser(ui.userEdit->text());
        authenticator->setPassword(ui.passwordEdit->text());
    }
}

在此示例中,我们将显示一个对话框,用户可在其中输入用户名和密码,或选择取消。取消操作将导致请求失败。

示例项目 @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.