使用QNetworkManager在QT中设计多个和嵌套GET / POST的最佳方法

时间:2016-09-02 06:40:15

标签: c++ qt post get qnetworkaccessmanager

我的疑问是关于正确设计实现多个嵌套GET / POST请求的软件。

假设您必须运行需要GET和POST的login()函数,然后使用需要两个GET的retrieveXYZ()(依此类推,可扩展)。

我想做的方式就像

mainwindow.cpp
    //code
    login();
    retrieveXYZ();
    //code

Mainwindow::login(){ 
    //code
    connect(nam, SIGNAL(finished()), this, SLOT(onGetLoginFinished()));
    nam->get(...);
}

Mainwindow::onGetLoginFinished(){
    //do stuff
    connect(nam, SIGNAL(finished()), this, SLOT(onPostLoginFinished()));
    nam->post(...);
}    

Mainwindow::onPostLoginFinished(){
    //do stuff
}

Mainwindow::retrieveXYZ(){
    //code
    connect(nam, SIGNAL(finished()), this, SLOT(onGet1RetrieveFinished()));
    nam->get();
    //code
}

Mainwindow::onGet1RetrieveXYZFinished(){
    //do stuff
    connect(nam, SIGNAL(finished()), this, SLOT(onGet2RetrieveFinished()));
    nam->get();
}    

或者我应该使用像QSignalMapper这样的东西? 哪种方法最正确/最有效?我见过人们使用sender()演员,但我不明白这一点。

基本上我想检索特定的回复finish()信号,而不是一般的(或qnam)

这种方法可能有效,但对我来说并不好看和干净

这是我们能得到的最好的吗?

http://www.johanpaul.com/blog/2011/07/why-qnetworkaccessmanager-should-not-have-the-finishedqnetworkreply-signal/

将连接方法移至回复?

1 个答案:

答案 0 :(得分:1)

我有类似的东西:

struct RequestResult {
    int httpCode;
    QByteArray content;
};

RequestResult
ExecuteRequest(const std::function<QNetworkReply*(QNetworkAccessManager&)>& action,
               const std::chrono::milliseconds& timeOut)
{
    QEventLoop eLoop;
    QTimer timeOutTimer;
    QNetworkAccessManager nam;

    QObject::connect(&timeOutTimer, &QTimer::timeout, &eLoop, &QEventLoop::quit);
    QObject::connect(&nam, &QNetworkAccessManager::finished, &eLoop, &QEventLoop::quit);

    timeOutTimer.setSingleShot(true);
    timeOutTimer.setInterval(timeOut.count());
    timeOutTimer.start();

    auto resetTimeOut = [&timeOutTimer]() { timeOutTimer.start(); };
    QNetworkReply* reply = action(nam);

    QObject::connect(reply, &QNetworkReply::uploadProgress, resetTimeOut);
    QObject::connect(reply, &QNetworkReply::downloadProgress, resetTimeOut);

    eLoop.exec();

    if (!timeOutTimer.isActive())
    {
        throw std::runtime_error("Time out"); // Probably custom exception
    }
    const int httpStatus
        = reply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute).toInt();
    auto content = TakeContent(*reply); // reply->readAll and decompression

    return RequestResult{httpStatus, content};
}

然后是get / delete / post / ..的函数,类似于

auto RequestGet(const QNetworkRequest& request) {
    return ExecuteRequest([&](QNetworkAccessManager& nam) { return nam.get(request); },
                          timeOut);
}

auto RequestDelete(const QNetworkRequest& request) {
    return ExecuteRequest([&](QNetworkAccessManager& nam) {
                              return nam.deleteResource(request);
                          },
                          timeOut);
}

auto RequestPost(const QNetworkRequest& request, QHttpMultiPart& multiPart)
{
    return ExecuteRequest([&](QNetworkAccessManager& nam) {
                              return nam.post(request, &multiPart);
                          },
                          timeOut);
}

然后,对于你的代码,我会做类似

的事情
Mainwindow::login()
{
    const auto getRes = RequestGet(..);
    // ...
    const auto postRes = RequestPost(..);
    // ...
}

如果你不想阻止电话,你可以使用线程 future