2016-09-02 34 views
1

Die Zweifel, die ich habe, ist über den richtigen Entwurf einer Software, die mehrere und verschachtelte GET/POST-Anfrage implementiert.Die beste Möglichkeit, multiple und verschachtelte GET/POST in QT mit QNetworkManager zu erstellen

Angenommen, Sie müssen eine login() -Funktion ausführen, die ein GET und einen POST erfordert, und dann retrieveXYZ(), was zwei GETs erfordert (und so weiter, skalierbar).

Die Art und Weise war ich thinkig es zu tun war wie

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(); 
}  

oder sollte ich so etwas wie QSignalMapper benutzen? Welches sind die richtigsten/effizientesten Methoden? Ich habe Leute gesehen, die sender() verwendet haben, aber ich habe den Punkt nicht verstanden.

Grundsätzlich würde Ich mag die besondere Antwort beendet (Signal) anstelle des allgemeinen eine (oder des qnam) abrufen

Diese Methode funktioniert, aber es ist nicht schön und sauber zu mir

Ist das Beste, was wir bekommen können?

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

Verschieben der connect Ansatz auf die Antwort?

+0

Haben Sie mehrere 'QNetworkAccessManager'? Welcher Teil ist seriell/parallel? – Jarod42

+0

Ich habe nur einen QNetworkAccessManager, was meinst du mit seriell/parallel? Ich habe keine parallele Anfrage, ich habe nur Serien. Das Problem ist, dass sie je nach Aufgaben unterschiedlich sind. Login() -Funktion ist ein Beispiel für ein GET gefolgt von einem POST – user217354

+0

Sie wollen also nur Anfrage blockieren? – Jarod42

Antwort

1

Ich habe so etwas wie:

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}; 
} 

Und dann Funktionen für get/löschen/post/.., die ähnlich

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); 
} 

Dann für Ihren Code, würde ich etwas tun, wie

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

und können Sie Thread verwenden und Zukunft wenn Sie Anrufe nicht blockieren möchten.

Verwandte Themen