Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QNetworkAccessManager reply is always empty
Forum Updated to NodeBB v4.3 + New Features

QNetworkAccessManager reply is always empty

Scheduled Pinned Locked Moved Solved General and Desktop
29 Posts 7 Posters 4.0k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    shokarta
    wrote on last edited by
    #1

    I am trying to read remote ini file to future use it into QSettings, however i keep getting empty reply.

        auto nam = new QNetworkAccessManager(this);
        QNetworkRequest request;
    //    request.setHeader(QNetworkRequest::ContentTypeHeader,"plain/text");
        request.setUrl(QUrl("http://somereachablelocation/settings.ini"));
    
        QNetworkReply* reply = nam->get(request);
        if (reply)
        {
            qDebug() << reply->readAll();
        }
        else {
            qDebug() << reply->error();
        }
    

    and i always have in debug only "".
    The ini file is reachable, because when i place the url http://somereachablelocation/settings.ini into the browser, it returns the content of the ini file.

    anything im forgetting?
    Im including:

    #include <QtNetwork/QNetworkAccessManager>
    #include <QtNetwork/QNetworkRequest>
    #include <QtNetwork/QNetworkReply>
    

    and in .pro file i of course have:

    QT += network
    

    Thank you

    1 Reply Last reply
    1
    • B Offline
      B Offline
      Bonnie
      wrote on last edited by Bonnie
      #12

      @shokarta Hello, sorry I was on my way home.
      Yes, I know sometimes we need to wait for the reply to be finished.
      It is not recommended, but possible.
      [Wow, this must be the most down-voted post I've ever posted, so you can see it is really not recommended.]
      And if you want to wait, you actually don't need to use lambda or slot.

      bool MSSQL::checkSettings()
      {
          //If you would call this function multiple times, it's better to declare a QNetworkAccessManager as a member variable
          QNetworkAccessManager nam;
      
          QNetworkRequest request(QUrl("http://somereachablle/settings.ini"));
          auto reply = nam.get(request);
      
          QEventLoop loop;
          QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
          loop.exec();
      
          reply->deleteLater();
          auto error = reply->error();
          if(error != QNetworkReply::NoError) {
              qDebug() << "network error:" << error << reply->errorString();
              return false;
          }
          QByteArray read = reply->readAll();
          if(read.isEmpty()) {
              qDebug() << "response is empty";
              return false;
          }
          QString fileName(QDir::currentPath() + "/" + settingsFile);
          QFile file(fileName);
          //[CHANGED]Remove QIODevice::Text to prevent line terminator mis-translating
          if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
              qDebug() << "file open error:" << file.error() << file.errorString();
              return false;
          }
          //NOTE: Don't use QTextStream to write QByteArray to file, that's not the right way even if the result is correct!!!
          file.write(read);
          file.close();
          return true;
      }
      
      Pablo J. RoginaP 1 Reply Last reply
      -2
      • B Offline
        B Offline
        Bonnie
        wrote on last edited by
        #2

        QNetworkAccessManager is asynchronous. When you read the reply, the request is not even started.
        You should connect to the finished() signal of the reply.

        1 Reply Last reply
        6
        • S Offline
          S Offline
          shokarta
          wrote on last edited by
          #3

          Hello Bonnie,
          I have tried severeal methods indiates what you just said.
          Can you please show real example? Preferably on the code I have shown, in order to make sure my mistake is not involved, because im trying thos for couple of days :(

          J.HilkJ 1 Reply Last reply
          0
          • S shokarta

            Hello Bonnie,
            I have tried severeal methods indiates what you just said.
            Can you please show real example? Preferably on the code I have shown, in order to make sure my mistake is not involved, because im trying thos for couple of days :(

            J.HilkJ Offline
            J.HilkJ Offline
            J.Hilk
            Moderators
            wrote on last edited by
            #4

            @shokarta

             auto nam = new QNetworkAccessManager(this);
                 
            connect(nam, &QNetworkAccessManager::finished,this, [](QNetworkReply *reply)->void {
                    qDebug() <<Q_FUNC_INFO << "QNetworkAccessManager::finished";
                    qDebug = reply->readAll();
                    reply->deleteLater();
                });
            
               QNetworkRequest request;
            //    request.setHeader(QNetworkRequest::ContentTypeHeader,"plain/text");
                request.setUrl(QUrl("http://somereachablelocation/settings.ini"));
            
                nam->get(request);
            

            Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


            Q: What's that?
            A: It's blue light.
            Q: What does it do?
            A: It turns blue.

            1 Reply Last reply
            1
            • S Offline
              S Offline
              shokarta
              wrote on last edited by
              #5
              This post is deleted!
              J.HilkJ 1 Reply Last reply
              0
              • S shokarta

                This post is deleted!

                J.HilkJ Offline
                J.HilkJ Offline
                J.Hilk
                Moderators
                wrote on last edited by
                #6

                @shokarta you're right, my bad.

                debug my be the wrong tool here lets print a hex dumb and check for error:

                connect(nam, &QNetworkAccessManager::finished,this, [](QNetworkReply *reply)->void {
                            qDebug() <<Q_FUNC_INFO << "QNetworkAccessManager::finished";
                            QByteArray ba = reply->readAll();
                            qDebug() << ba.toHex(' ');
                
                            qDebug() << "Error ? " reply->error()
                            reply->deleteLater();
                        });
                

                It's probably also better to listen to pot errors of the network manager, those do emit error signals, listen to that ;)


                Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                Q: What's that?
                A: It's blue light.
                Q: What does it do?
                A: It turns blue.

                1 Reply Last reply
                3
                • S Offline
                  S Offline
                  shokarta
                  wrote on last edited by
                  #7

                  @J-Hilk said in QNetworkAccessManager reply is always empty:

                  reply->error()

                  can I also save the error to the variable?
                  QString replyError = reply->error();

                  of course not like this, but how it would be the proper way?

                  J.HilkJ 1 Reply Last reply
                  0
                  • S shokarta

                    @J-Hilk said in QNetworkAccessManager reply is always empty:

                    reply->error()

                    can I also save the error to the variable?
                    QString replyError = reply->error();

                    of course not like this, but how it would be the proper way?

                    J.HilkJ Offline
                    J.HilkJ Offline
                    J.Hilk
                    Moderators
                    wrote on last edited by
                    #8

                    @shokarta
                    https://doc.qt.io/qt-5/qnetworkreply.html#error

                    error() returns a QNetworkReply::NetworkError

                    therefore:

                    QNetworkReply::NetworkError  myError = reply->error();
                    

                    Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                    Q: What's that?
                    A: It's blue light.
                    Q: What does it do?
                    A: It turns blue.

                    1 Reply Last reply
                    3
                    • J.HilkJ Offline
                      J.HilkJ Offline
                      J.Hilk
                      Moderators
                      wrote on last edited by
                      #9

                      I have the feeling, you're not overly familiar with lambdas, so lets split this properly into class functions.

                      add the following into your header file:

                      privat slots:
                           void onNetworkReplyFinished(QNetworkReply *reply);
                      

                      in your cpp file add the following body:

                      void myClassName:: onNetworkReplyFinished(QNetworkReply *reply)
                      {
                           qDebug() <<Q_FUNC_INFO << "QNetworkAccessManager::finished";
                                       QByteArray ba = reply->readAll();
                                       qDebug() << ba.toHex(' ');
                           
                                       qDebug() << "Error ? " reply->error()
                                       reply->deleteLater();
                      }
                      

                      change the connect to:

                       auto nam = new QNetworkAccessManager(this);
                           
                      connect(nam, &QNetworkAccessManager::finished,this, & myClassName:: onNetworkReplyFinished);
                      
                         QNetworkRequest request;
                      //    request.setHeader(QNetworkRequest::ContentTypeHeader,"plain/text");
                          request.setUrl(QUrl("http://somereachablelocation/settings.ini"));
                      
                          nam->get(request);
                      

                      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                      Q: What's that?
                      A: It's blue light.
                      Q: What does it do?
                      A: It turns blue.

                      1 Reply Last reply
                      3
                      • S Offline
                        S Offline
                        shokarta
                        wrote on last edited by
                        #10

                        @J-Hilk said in QNetworkAccessManager reply is always empty:

                        I have the feeling, you're not overly familiar with lambdas, so lets split this properly into class functions.

                        You are right, im not...
                        However after evaluation, i dont see a reason why shouldnt I use it on my purposes just in a simple custom function as Im using it:

                        bool MSSQL::checkSettings()
                        {
                            auto nam = new QNetworkAccessManager(this);
                            connect(nam, &QNetworkAccessManager::finished, this, [](QNetworkReply *reply)->void {
                                QByteArray iniOutput = reply->readAll();
                                QNetworkReply::NetworkError iniError = reply->error();
                                reply->deleteLater();
                            });
                            QNetworkRequest request;
                            //request.setHeader(QNetworkRequest::ContentTypeHeader,"plain/text");
                            request.setUrl(QUrl("http://somereachablle/settings.ini"));
                            nam->get(request);
                        
                            if(iniError)
                            {
                                qDebug() << "Terminal DB Error: Remote INI file not reachable: " << iniError;
                                return false;
                            }
                            else {
                                QString fileName(QDir::currentPath() + "\\" + settingsFile);
                                QFile file(fileName);
                                file.open(QIODevice::ReadWrite | QIODevice::Text);
                                QTextStream out(&file);
                                out << iniOutput;
                                file.close();
                                return true;
                            }
                        }
                        

                        but as expected, unfortunately it does not recognize variables iniError and iniOutput

                        I kinda understand why, however I dont know how to modify this to the logic of:

                        1. try to open the network file
                        2. wait (even sleep if needed) for reply
                        3. if no error save the readAll() to the variable
                        4. if error also store it in the variable so i can print it anytime later

                        I know im asking a lot, but this should be quite easly possible, right? just dont know the correct approach...
                        Kindly thank you

                        J.HilkJ 1 Reply Last reply
                        0
                        • S shokarta

                          @J-Hilk said in QNetworkAccessManager reply is always empty:

                          I have the feeling, you're not overly familiar with lambdas, so lets split this properly into class functions.

                          You are right, im not...
                          However after evaluation, i dont see a reason why shouldnt I use it on my purposes just in a simple custom function as Im using it:

                          bool MSSQL::checkSettings()
                          {
                              auto nam = new QNetworkAccessManager(this);
                              connect(nam, &QNetworkAccessManager::finished, this, [](QNetworkReply *reply)->void {
                                  QByteArray iniOutput = reply->readAll();
                                  QNetworkReply::NetworkError iniError = reply->error();
                                  reply->deleteLater();
                              });
                              QNetworkRequest request;
                              //request.setHeader(QNetworkRequest::ContentTypeHeader,"plain/text");
                              request.setUrl(QUrl("http://somereachablle/settings.ini"));
                              nam->get(request);
                          
                              if(iniError)
                              {
                                  qDebug() << "Terminal DB Error: Remote INI file not reachable: " << iniError;
                                  return false;
                              }
                              else {
                                  QString fileName(QDir::currentPath() + "\\" + settingsFile);
                                  QFile file(fileName);
                                  file.open(QIODevice::ReadWrite | QIODevice::Text);
                                  QTextStream out(&file);
                                  out << iniOutput;
                                  file.close();
                                  return true;
                              }
                          }
                          

                          but as expected, unfortunately it does not recognize variables iniError and iniOutput

                          I kinda understand why, however I dont know how to modify this to the logic of:

                          1. try to open the network file
                          2. wait (even sleep if needed) for reply
                          3. if no error save the readAll() to the variable
                          4. if error also store it in the variable so i can print it anytime later

                          I know im asking a lot, but this should be quite easly possible, right? just dont know the correct approach...
                          Kindly thank you

                          J.HilkJ Offline
                          J.HilkJ Offline
                          J.Hilk
                          Moderators
                          wrote on last edited by J.Hilk
                          #11

                          @shokarta here's the problem, the network call is asynchronous, so you can't (shouldn't) wait for the reply and return then.

                          go with the approach of a separate function inside your class that is treated as a callback of sorts for the NetworkaccessManager

                          void MSSQL::onNetworkReplyFinished(QNetworkReply *reply)
                          {
                               qDebug() <<Q_FUNC_INFO << "QNetworkAccessManager::finished";
                                           QByteArray ba = reply->readAll();
                                           qDebug() << ba.toHex(' ');
                                            QNetworkReply::NetworkError iniError = reply->error();
                              
                                           reply->deleteLater();
                          
                          if(iniError)
                              {
                                  qDebug() << "Terminal DB Error: Remote INI file not reachable: " << iniError;
                                  emit NetworkAccessWasSuccessful(false);
                              }
                              else {
                                  QString fileName(QDir::currentPath() + "\\" + settingsFile);
                                  QFile file(fileName);
                                  file.open(QIODevice::ReadWrite | QIODevice::Text);
                                  file.write(ba);
                                  file.close();
                                  emit NetworkAccessWasSuccessful(true);;
                              }
                          }
                          

                          Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


                          Q: What's that?
                          A: It's blue light.
                          Q: What does it do?
                          A: It turns blue.

                          1 Reply Last reply
                          2
                          • B Offline
                            B Offline
                            Bonnie
                            wrote on last edited by Bonnie
                            #12

                            @shokarta Hello, sorry I was on my way home.
                            Yes, I know sometimes we need to wait for the reply to be finished.
                            It is not recommended, but possible.
                            [Wow, this must be the most down-voted post I've ever posted, so you can see it is really not recommended.]
                            And if you want to wait, you actually don't need to use lambda or slot.

                            bool MSSQL::checkSettings()
                            {
                                //If you would call this function multiple times, it's better to declare a QNetworkAccessManager as a member variable
                                QNetworkAccessManager nam;
                            
                                QNetworkRequest request(QUrl("http://somereachablle/settings.ini"));
                                auto reply = nam.get(request);
                            
                                QEventLoop loop;
                                QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
                                loop.exec();
                            
                                reply->deleteLater();
                                auto error = reply->error();
                                if(error != QNetworkReply::NoError) {
                                    qDebug() << "network error:" << error << reply->errorString();
                                    return false;
                                }
                                QByteArray read = reply->readAll();
                                if(read.isEmpty()) {
                                    qDebug() << "response is empty";
                                    return false;
                                }
                                QString fileName(QDir::currentPath() + "/" + settingsFile);
                                QFile file(fileName);
                                //[CHANGED]Remove QIODevice::Text to prevent line terminator mis-translating
                                if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
                                    qDebug() << "file open error:" << file.error() << file.errorString();
                                    return false;
                                }
                                //NOTE: Don't use QTextStream to write QByteArray to file, that's not the right way even if the result is correct!!!
                                file.write(read);
                                file.close();
                                return true;
                            }
                            
                            Pablo J. RoginaP 1 Reply Last reply
                            -2
                            • S Offline
                              S Offline
                              shokarta
                              wrote on last edited by
                              #13

                              @Bonnie thank you, this works very fine...
                              Just for precausion, is it possible to sed timeout for the waiting loop?

                              B 1 Reply Last reply
                              0
                              • S shokarta

                                @Bonnie thank you, this works very fine...
                                Just for precausion, is it possible to sed timeout for the waiting loop?

                                B Offline
                                B Offline
                                Bonnie
                                wrote on last edited by Bonnie
                                #14

                                @shokarta
                                The QEventLoop itself doesn't have timeout function.
                                But you could set a QTimer

                                QEventLoop loop;
                                QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
                                QTimer::singleShot(30 * 1000, &loop, &QEventLoop::quit);
                                loop.exec();
                                
                                reply->deleteLater();
                                if(!reply->isFinished()) {
                                    qDebug() << "timeout";
                                    return false;
                                }
                                
                                1 Reply Last reply
                                0
                                • S Offline
                                  S Offline
                                  shokarta
                                  wrote on last edited by
                                  #15

                                  @Bonnie sweet, not its realy ok :)
                                  One very last thing, I have noticed that the read content contains new rows as "\r\n" which after write() makes double empty rows instead of single ones.

                                  Im ok to fix it by:

                                      int start_pos = 0;
                                      QByteArray from("\r\n");
                                      QByteArray to("\n");
                                      while((start_pos = read.indexOf(from, start_pos)) != -1) {
                                          read.replace(start_pos, from.length(), to);
                                          start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
                                      }
                                  

                                  but im wondering if this can be prevented by setting header maybe?

                                  1 Reply Last reply
                                  0
                                  • B Offline
                                    B Offline
                                    Bonnie
                                    wrote on last edited by
                                    #16

                                    Are you running the code in Windows?
                                    And the original text from the ini on the network should be "\n"?
                                    This is what QIODevice::Text supposed to do in Windows: replace "\n" to "\r\n" when writing.

                                    1 Reply Last reply
                                    0
                                    • S Offline
                                      S Offline
                                      shokarta
                                      wrote on last edited by
                                      #17

                                      Yes on Windows,
                                      however file is stored on linux network and i odnt know if there are \n or \r\n
                                      but when i qDebug() << read; even before QIODevice::Text i can see there are \r\n, therefore.
                                      Then i replace it with just \n and then qhen opening file via QIODevice::Text it writes just fine... therefore QIODevice::Text has no impact...

                                      B 1 Reply Last reply
                                      0
                                      • S shokarta

                                        Yes on Windows,
                                        however file is stored on linux network and i odnt know if there are \n or \r\n
                                        but when i qDebug() << read; even before QIODevice::Text i can see there are \r\n, therefore.
                                        Then i replace it with just \n and then qhen opening file via QIODevice::Text it writes just fine... therefore QIODevice::Text has no impact...

                                        B Offline
                                        B Offline
                                        Bonnie
                                        wrote on last edited by Bonnie
                                        #18

                                        @shokarta
                                        I've tested on my Windows, QIODevice::Text does do what it is supposed to do.
                                        The thing is, "\r\n" is the right line terminator in Windows, so you will see a normal line break with a "\r\n".
                                        But if your original text is "\r\n", then it will be translated to "\r\r\n", that's not right.
                                        So I think you can just delete that QIODevice::Text flag.

                                        1 Reply Last reply
                                        0
                                        • B Bonnie

                                          @shokarta Hello, sorry I was on my way home.
                                          Yes, I know sometimes we need to wait for the reply to be finished.
                                          It is not recommended, but possible.
                                          [Wow, this must be the most down-voted post I've ever posted, so you can see it is really not recommended.]
                                          And if you want to wait, you actually don't need to use lambda or slot.

                                          bool MSSQL::checkSettings()
                                          {
                                              //If you would call this function multiple times, it's better to declare a QNetworkAccessManager as a member variable
                                              QNetworkAccessManager nam;
                                          
                                              QNetworkRequest request(QUrl("http://somereachablle/settings.ini"));
                                              auto reply = nam.get(request);
                                          
                                              QEventLoop loop;
                                              QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
                                              loop.exec();
                                          
                                              reply->deleteLater();
                                              auto error = reply->error();
                                              if(error != QNetworkReply::NoError) {
                                                  qDebug() << "network error:" << error << reply->errorString();
                                                  return false;
                                              }
                                              QByteArray read = reply->readAll();
                                              if(read.isEmpty()) {
                                                  qDebug() << "response is empty";
                                                  return false;
                                              }
                                              QString fileName(QDir::currentPath() + "/" + settingsFile);
                                              QFile file(fileName);
                                              //[CHANGED]Remove QIODevice::Text to prevent line terminator mis-translating
                                              if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
                                                  qDebug() << "file open error:" << file.error() << file.errorString();
                                                  return false;
                                              }
                                              //NOTE: Don't use QTextStream to write QByteArray to file, that's not the right way even if the result is correct!!!
                                              file.write(read);
                                              file.close();
                                              return true;
                                          }
                                          
                                          Pablo J. RoginaP Offline
                                          Pablo J. RoginaP Offline
                                          Pablo J. Rogina
                                          wrote on last edited by
                                          #19

                                          @Bonnie said in QNetworkAccessManager reply is always empty:

                                          Yes, I know sometimes we need to wait for the reply to be finished.

                                          So connect the QNetworkReply::finished() signal then...

                                          QEventLoop loop;

                                          QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);

                                          loop.exec();

                                          It doesn't look a pretty good idea to mess with the event loop. And not needed either

                                          Upvote the answer(s) that helped you solve the issue
                                          Use "Topic Tools" button to mark your post as Solved
                                          Add screenshots via postimage.org
                                          Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

                                          B 1 Reply Last reply
                                          2
                                          • Pablo J. RoginaP Pablo J. Rogina

                                            @Bonnie said in QNetworkAccessManager reply is always empty:

                                            Yes, I know sometimes we need to wait for the reply to be finished.

                                            So connect the QNetworkReply::finished() signal then...

                                            QEventLoop loop;

                                            QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);

                                            loop.exec();

                                            It doesn't look a pretty good idea to mess with the event loop. And not needed either

                                            B Offline
                                            B Offline
                                            Bonnie
                                            wrote on last edited by
                                            #20

                                            @Pablo-J-Rogina said in QNetworkAccessManager reply is always empty:

                                            It doesn't look a pretty good idea to mess with the event loop. And not needed either

                                            There are cases that we need to get response synchronously.
                                            In the OP's case for example, the function need to return a result of true / false.
                                            And this is a typical usage of QEventLoop: to wait until a signal.
                                            I've already said it is not recommended.
                                            But anyone should be free to use it if he insists a synchronous request.

                                            1 Reply Last reply
                                            0

                                            • Login

                                            • Login or register to search.
                                            • First post
                                              Last post
                                            0
                                            • Categories
                                            • Recent
                                            • Tags
                                            • Popular
                                            • Users
                                            • Groups
                                            • Search
                                            • Get Qt Extensions
                                            • Unsolved