Frage zu/Problem mit QNetworkAccessManager

Alles rund um die Programmierung mit Qt
Antworten
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Frage zu/Problem mit QNetworkAccessManager

Beitrag von pfid »

Ich habe hier ein seltsames Problem mit dem QNetworkAccessManager. Ich bin dabei ein Widget zu entwickeln, dass das Google Calendar Protokoll implementiert. Momentan ist das Einloggen sowie Abrufen von Kalendern und Ereignissen fertig, basieren auf einer Reihe von POST und GET Requests.

Der richtige Ablauf ist in etwa so (pseudo):

Code: Alles auswählen

manager->post(loginURL, loginData);

-> HTTP 200 (OK)

manager->get(calenderFeedURL);

-> HTTP 302 (redirect) -> neue calenderFeedURL mit session parameter

manager->get(neueCalenderFeedURL);

-> HTTP 200 (OK)

*reply auswerten und kalenderliste speichern*

manager->get(eventsFeedURL);

-> HTTP 302 (redirect) -> neue calenderFeedURL mit session parameter

manager->get(neueEventsFeedURL);

*reply auswerten und kalenderliste speichern*
Das Problem ist nun, dass ich an zufälligen Stellen einen HTTP400/Bad Request bekomme. Dabei ist die Stelle Zufall und bei jedem Programmstart anders, manchmal läufts auch fehlerfrei durch.

Prinzipiell hab ichs so gecoded:

Code: Alles auswählen

MainClass::MainClass()
{
   lastRequest = 0;
   manager = new QNetworkAccessManager(this);
   connect(manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), this, SLOT(onAuthenticationRequired(QNetworkReply*,QAuthenticator*)));
   connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(onFinished(QNetworkReply*)));
   connect(manager, SIGNAL(proxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)), this, SLOT(onProxyAuthenticationRequired(QNetworkProxy,QAuthenticator*)));
   connect(manager, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(onSslErrors(QNetworkReply*,QList<QSslError>)));

...
Request vorbereiten:

Code: Alles auswählen

int MainClass::prepare(const QString& url)
{
   delete lastRequest;
   lastRequest = new QNetworkRequest(QUrl(url));

   if (!authToken.isEmpty())
   {
      lastRequest->setRawHeader("Authorization", authToken);
      lastRequest->setRawHeader("GData-Version", "2");
   }

   return success;
}
Einloggen:

Code: Alles auswählen

int MainClass::login(const QString& aEmail, const QString& aPassword)
{
   DataPacket data;             // request body

   prepare(urls[urlLogin]);     // s.o.

   /* body vorbereiten */

   manager->post(*lastRequest, data.getData());

   return success;
}

Die restlichen Methoden sind eigentlich simple GETs auf die entsprechende Feed-URL:


Kalenderliste:

Code: Alles auswählen

int MainClass::getCalendarList()
{
   ...
   /* some error checks */

   prepare(urls[urlCalendarListFull]);

   manager->get(*lastRequest);

   return success;
}
Eventliste analog.

Im onFinished() Slot werte ich die Antworten aus. Bei Erfolg wird am Ende des Slots die jeweils nächste Anfrage abgeschickt. D.h. nach erfoglreichem Login folgt ein GET auf die CalenderFeeds URL, nachdem die Kalenderliste empfangen wurde ein GET auf die EventsFeed URL.

Ist das Vorgehen so falsch, oder sieht jemand wo ich nach dem Fehler suchen müsste?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Was liefert data.getData() zurück? Ein QByteArray? Oder doch aus Versehen ein QIODevice?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Christian81 hat geschrieben:Was liefert data.getData() zurück? Ein QByteArray? Oder doch aus Versehen ein QIODevice?
Sorry vergessen zu erwähnen, ist ein QByteArray.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Schade, nein dann habe ich auf Anhieb keine Idee.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

Ich verstehs nicht... ich könnte mir vorstellen, dass es damit zusammenhängt, dass ich die nächste Anfrage direkt im finished-Slot abschicke. Am Ende des Slots rufe ich

reply->deleteLater();

auf, danach wird die nächste POST oder GET Anfrage abgeschickt. Laut Docs wird das reply-Objekt nun gelöscht wenn der Programmablauf in die Eventloop zurückkehrt. Das sollte doch der Fall sein, nachdem die nächste Anfrage geschickt wurde. Führt das Löschen des reply-Objekts an dieser Stelle dann zu dem Problem? (Gar nicht löschen oder per delete löschen bringt auch nichts...)

Ich bekomm hier an völlig zufälligen Stellen unterschiedliche Fehler; mal 400/Bad Request, mal 399/Data corrupted, mal auch Statuscode 0 mit einfach einem leeren reply-Objekt.

Wie benutzt man den QNetworkAccessManager denn richtig? Irgendwas schein ich ja grundlegend falsch zu machen, sonst würds mir nicht so um die Ohren fliegen. :?

Ich kriegs einfach nicht hin...

[edit] hier der finished slot:

Code: Alles auswählen

void MainClass::onFinished(QNetworkReply* reply)
{
   int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

   qDebug() << "FINISHED" << statusCode;

   switch (statusCode)
   {
      case 200:                               // OK
      {
         // process reply

         if (!isLoggedIn())
            storeAuthorization(reply);

         switch (state)
         {
            case stGetCalendars:
            {
               parseCalendarList(reply);
               break;
            }
            case stGetEvents:
            {
               parseEventList(reply);
               break;
            }
         }

         break;
      }

      case 302:                               // redirect (Location: [URL])
      {
         qDebug() << "redirected to" << locationOf(reply);
         prepare(locationOf(reply));
         manager->get(*lastRequest);

         break;
      }

      case 400:                               // bad request
      {
         QMessageBox::warning(this, "Error", "Network error (HTTP400/Bad Request)");
         break;
      }

      case 403:                               // permission denied
      {
         QMessageBox::warning(this, "Permission denied", "Username or password invalid");
         break;
      }

      default:
      {
         QByteArray replyData = reply->readAll();
         qDebug() << "Unknown response" << replyData;
         break;
      }
   }

   reply->deleteLater();

   // do anything afterwards?

   after();            // <-- nächste anfrage per post()/get()

   qDebug() << "request done";
}
Antworten