【问题标题】:QNetworkAccessManager never emits finished() signalQNetworkAccessManager 从不发出 finished() 信号
【发布时间】:2023-03-31 10:33:01
【问题描述】:

我正在为一个项目开发一个模块,其中 HTTP GET 请求用于检索一些 XML 数据,然后将其转换为另一种格式并发送到子系统。

目前我写的代码如下:

CMakeLists.txt:

project(HttpDemo)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_BUILD_TYPE Debug)

#find_package(Qt5Widgets)
find_package(Qt5Core)
find_package(Qt5Network)

set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

aux_source_directory(. SRC_LIST)
add_executable(${PROJECT_NAME} ${SRC_LIST})
qt5_use_modules(${PROJECT_NAME} Core Network) #Gui Widgets

ma​​in.cpp

#include <QtCore>
#include <QtNetwork>

class HttpHandler : public QObject
{
    Q_OBJECT
public:
    HttpHandler(QObject* parent=Q_NULLPTR) : QObject(parent)
    {
        QObject::connect(&nm, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*)));
        qDebug() << QSslSocket::sslLibraryBuildVersionString();
    }
private:
    QNetworkAccessManager nm;
public slots:
    void post(QString urlLink)
    {
        QUrl url(urlLink);
        QNetworkRequest request(url);
        QSslConfiguration sslConf;
        sslConf.setProtocol(QSsl::SslV3);
        request.setSslConfiguration(sslConf);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencded");

        QUrlQuery query;
        query.addQueryItem("client_id", "1234");
        query.addQueryItem("code", "abcd");

        QUrl params;
        params.setQuery(query);

        nm.post(request, params.toEncoded());
    }

    void get(QString urlLink)
    {
        QUrl url(urlLink);
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

        nm.get(request);
    }

    void replyFinished(QNetworkReply* reply)
    {
        QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        if(statusCode.isValid())
        {
            // Print or catch the status code
            QString status = statusCode.toString(); // or status_code.toInt();
            qDebug() << status;
            qDebug() << QString::fromStdString(reply->readAll().toStdString());
        }
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    HttpHandler hh;
    hh.get("SOME_URL");

    return a.exec();
}

#include "main.moc"

对于SOME_URL,我尝试了很多链接,所有这些链接都可以正常工作,比如说Firefox 的Http Requester 插件。我明白了:

“OpenSSL 1.0.1j 2014 年 10 月 15 日”

qt.network.ssl:QSslSocket:无法解析 SSLv2_client_method

qt.network.ssl:QSslSocket:无法解析 SSLv2_server_method

根据互联网权威机构的说法,这应该不是问题。有一件事是肯定的 - 我的replyFinished(QNetworkReply*) 插槽没有被触发,尽管它连接到QNetworkAccessManagerfinished() 信号。这意味着无论出于何种原因都不会发出信号。将QSslConfiguration 更改为不同的QSsl::SslProtocol 不会对结果产生影响。


更新(根据 cmets 的要求):

以下代码使用readyRead() 并动态分配回复。结果 - 与上面相同。

#include <QtCore>
#include <QtNetwork>

class HttpHandler : public QObject
{
    Q_OBJECT
public:
    HttpHandler(QObject* parent=Q_NULLPTR) : QObject(parent)
    {
        qDebug() << QSslSocket::sslLibraryBuildVersionString();
        this->manager = new QNetworkAccessManager(this);
        this->reply = Q_NULLPTR;
    }
private:
    QNetworkAccessManager* manager;
    QNetworkReply* reply;
signals:
    void finished();
public slots:
    void post(QString urlLink)
    {
        QUrl url(urlLink);
        QNetworkRequest request(url);
        QSslConfiguration sslConf;
        sslConf.setProtocol(QSsl::SslV2);
        request.setSslConfiguration(sslConf);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

        QUrlQuery query;
        query.addQueryItem("client_id", "1234");
        query.addQueryItem("code", "abcd");

        QUrl params;
        params.setQuery(query);

        manager->post(request, params.toEncoded());
    }

    void get(QString urlLink)
    {
        QUrl url(urlLink);
        QNetworkRequest request(url);
        request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

        this->reply = manager->get(request);
        QObject::connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
    }

    void slotReadyRead()
    {
        qDebug() << "Hello"; // I never land here
    }

    void replyFinished(QNetworkReply* reply)
    {
        QVariant statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
        if(statusCode.isValid())
        {
            QString status = statusCode.toString(); // or status_code.toInt();
            qDebug() << status;
            qDebug() << QString::fromStdString(reply->readAll().toStdString());
        }

        emit finished();
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    HttpHandler *hh = new HttpHandler(&a);
    QObject::connect(hh, SIGNAL(finished()), &a, SLOT(quit()));

    hh->get("http://httpbin.org/ip"); // or any other httpbin.org endpoint

    return a.exec();
}

#include "main.moc"

更新 2:

我刚刚找到了一个example in the Qt documentation。下载、编译并运行了这个东西——同样的错误,但它可以工作。

【问题讨论】:

  • 你的OpenSsl库会不会有问题,它连接到Qt?
  • 有可能,但我不知道如何“调试”这个问题。我读过 SSL 库可以静态链接到 Qt,这样您就可以发布自己的版本,但我不确定这会给我的工作带来多少工作。
  • 你可以试试看void sslErrors(QNetworkReply *reply, const QList&lt;QSslError&gt; &amp;errors),也许在那里你能找到什么?或者也许是 ar NetworkError QNetworkReply::error() const
  • 我实际上尝试连接sslErrors() 信号,但它从未发出。 :-/ 调用error() 毫无意义,因为我什至没有进入replyFinished() 插槽(因为似乎没有发出允许我这样做的信号)。
  • 试着把你的信号改成readyRead(),看看有没有数据在里面?

标签: c++ qt http ssl http-get


【解决方案1】:

问题已解决(请参阅here)。基本上问题出在公司的代理上。我的一位同事试了一下,用 HTTPS 替换了 HTTP(即使链接是 HTTP),它突然就工作了。然后它让我们震惊了——该公司的代理缓存 HTTP(并且还做其他事情),这会导致巨大的延迟,如果超时容限足够小,QNetworkAccessManager 将返回套接字超时。

使用QNetworkProxyFactory::setUseSystemConfiguration(true) 启用代理的方式不会使您的应用程序依赖于代码中的配置,而是依赖于系统的配置。

【讨论】:

  • 很高兴听到您找到了问题的原因。您可以通过解释如何诊断它,特别是当其他地方看到该问题时,哪些证据可以识别该问题,从而使您的答案对未来的读者更有帮助。并请用摘要描述替换/增强该链接,以便您的答案本身是完整的;谢谢。
猜你喜欢
  • 1970-01-01
  • 2011-02-16
  • 1970-01-01
  • 2012-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多