Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. QML XMLHttpRequest vs QNetworkAccessManager requests
QtWS25 Last Chance

QML XMLHttpRequest vs QNetworkAccessManager requests

Scheduled Pinned Locked Moved Solved QML and Qt Quick
xmlhttprequestqnetworkaccessm
4 Posts 2 Posters 585 Views
  • 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
    SamGrant - Auterion
    wrote on last edited by
    #1

    Building a QT/QML application that issues GET and POST requests to a custom locally hosted service.

    When the GET/POST requests are issued via C++/QNetworkAccessManager, they go through without issues. I mean that the requests hit the service, and I get a response back that is expected.

    However, when issuing the requests via QML/XMLHttpRequest (or even via a Q_INVOKABLE accessible QNetworkAccessManager), the GETs 'work' ok, but the POSTs do not.

    What I mean is that the POSTs fail. The service responds that there is no JSON data attached to the POST.

    If I examine the HTTP packets with WireShark, I see that when initiating the calls from QML/Javascript... the GET and POST packets are sent as 'Continuation'. With the POST, the JSON data is in a later packet. When checking the same packets when the calls are initiated from C++, the packets are NOT marked as 'Continuation', and the POST packet contains all the JSON data as intended.

    Also, the QML/Javascript-initiated HTTP packets are larger (4x) than the same C++-initiated packets.

    C++ QNetworkAccessManager POST:

    QNetworkRequest request(url);
    if (!_appendToken(request)) // <== calls setRawHeader("Authorization"...
        return;
    
    qCDebug(RESTCoTClientLog) << "_sendPostRequest" << url;
    qCDebug(RESTCoTClientLog) << "_sendPostRequest" << jsonData;
    
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
    QNetworkReply *reply = _networkManager->post(request, jsonData);
    
    // Connect signals and slots to handle the response
    connect(reply, &QNetworkReply::finished, this, &RESTCoTClient::_onPostRequestFinished);
    connect(reply, &QNetworkReply::errorOccurred, this, &RESTCoTClient::_onNetworkError);
    

    Wireshark C++ POST Packet:
    4ef4bcca-b026-4f9f-8076-c1692b4f0833-image.png
    XMLHttpRequest POST:

    var xhrPost = new XMLHttpRequest()
        xhrPost.open("POST", url,true)
        xhrPost.onreadystatechange = function () {
            if (xhrPost.readyState === XMLHttpRequest.DONE) {
                if (xhrPost.status === 200) {
                    var xhrRepsonse = xhrPost.responseText
                    console.log("INFO: RESTCotClient - XMLHttpRequest response => " + xhrRepsonse)
                    _processXhrResponse(xhrRepsonse)
                } else {
                    console.log("ERROR: RESTCotClient - XMLHttpRequest Failed ("
                                + xhrType + ") => " + xhrPost.statusText)
                    console.log("ERROR: RESTCotClient - XMLHttpRequest Failed ("
                                + xhrType + ") => " + xhrPost.responseText)
                    _processXhrError()
                }
            }
    }
    var jsonData = JSON.stringify(jsonObj)
    
    xhrPost.setRequestHeader("Content-Type", "application/json")
    
    xhrType = "postRequest"
    _appendToken(xhrPost)  // <== calls setRequestHeader("Authorization"...
    
    console.log("INFO: RESTCotClient - _sendPostRequest => " + jsonData)
    
    
    xhrPost.send(jsonData)
    

    Wireshark QML POST Packet:
    14bbe8ea-c7d0-4095-95ee-031aa8dd5bfe-image.png

    Also, as stated higher up, if I set up a Q_INVOKABLE that calls the same QNetworkAccessManager function as above from QML/Javascript... I get the same result as if I were calling XMLHttpRequest directly.

    And, interestingly enough, it appears that QML XMLHttpRequest directly calls QNetworkAccessManager under the hood.

    So... what gives? Why are my XMLHttpRequest packets being broken up? Yes, I tested with Firefox & Chrome, sending the exact same XMLHttpRequest and both passed without issues.

    Tried C++ QNetworkAccessManager calls - Works
    Tried QML Javascript XMLHttpRequest calls - Fails
    Tried Q_INVOKABLE calls - Fails

    jeremy_kJ 1 Reply Last reply
    0
    • S SamGrant - Auterion

      Building a QT/QML application that issues GET and POST requests to a custom locally hosted service.

      When the GET/POST requests are issued via C++/QNetworkAccessManager, they go through without issues. I mean that the requests hit the service, and I get a response back that is expected.

      However, when issuing the requests via QML/XMLHttpRequest (or even via a Q_INVOKABLE accessible QNetworkAccessManager), the GETs 'work' ok, but the POSTs do not.

      What I mean is that the POSTs fail. The service responds that there is no JSON data attached to the POST.

      If I examine the HTTP packets with WireShark, I see that when initiating the calls from QML/Javascript... the GET and POST packets are sent as 'Continuation'. With the POST, the JSON data is in a later packet. When checking the same packets when the calls are initiated from C++, the packets are NOT marked as 'Continuation', and the POST packet contains all the JSON data as intended.

      Also, the QML/Javascript-initiated HTTP packets are larger (4x) than the same C++-initiated packets.

      C++ QNetworkAccessManager POST:

      QNetworkRequest request(url);
      if (!_appendToken(request)) // <== calls setRawHeader("Authorization"...
          return;
      
      qCDebug(RESTCoTClientLog) << "_sendPostRequest" << url;
      qCDebug(RESTCoTClientLog) << "_sendPostRequest" << jsonData;
      
      request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
      QNetworkReply *reply = _networkManager->post(request, jsonData);
      
      // Connect signals and slots to handle the response
      connect(reply, &QNetworkReply::finished, this, &RESTCoTClient::_onPostRequestFinished);
      connect(reply, &QNetworkReply::errorOccurred, this, &RESTCoTClient::_onNetworkError);
      

      Wireshark C++ POST Packet:
      4ef4bcca-b026-4f9f-8076-c1692b4f0833-image.png
      XMLHttpRequest POST:

      var xhrPost = new XMLHttpRequest()
          xhrPost.open("POST", url,true)
          xhrPost.onreadystatechange = function () {
              if (xhrPost.readyState === XMLHttpRequest.DONE) {
                  if (xhrPost.status === 200) {
                      var xhrRepsonse = xhrPost.responseText
                      console.log("INFO: RESTCotClient - XMLHttpRequest response => " + xhrRepsonse)
                      _processXhrResponse(xhrRepsonse)
                  } else {
                      console.log("ERROR: RESTCotClient - XMLHttpRequest Failed ("
                                  + xhrType + ") => " + xhrPost.statusText)
                      console.log("ERROR: RESTCotClient - XMLHttpRequest Failed ("
                                  + xhrType + ") => " + xhrPost.responseText)
                      _processXhrError()
                  }
              }
      }
      var jsonData = JSON.stringify(jsonObj)
      
      xhrPost.setRequestHeader("Content-Type", "application/json")
      
      xhrType = "postRequest"
      _appendToken(xhrPost)  // <== calls setRequestHeader("Authorization"...
      
      console.log("INFO: RESTCotClient - _sendPostRequest => " + jsonData)
      
      
      xhrPost.send(jsonData)
      

      Wireshark QML POST Packet:
      14bbe8ea-c7d0-4095-95ee-031aa8dd5bfe-image.png

      Also, as stated higher up, if I set up a Q_INVOKABLE that calls the same QNetworkAccessManager function as above from QML/Javascript... I get the same result as if I were calling XMLHttpRequest directly.

      And, interestingly enough, it appears that QML XMLHttpRequest directly calls QNetworkAccessManager under the hood.

      So... what gives? Why are my XMLHttpRequest packets being broken up? Yes, I tested with Firefox & Chrome, sending the exact same XMLHttpRequest and both passed without issues.

      Tried C++ QNetworkAccessManager calls - Works
      Tried QML Javascript XMLHttpRequest calls - Fails
      Tried Q_INVOKABLE calls - Fails

      jeremy_kJ Offline
      jeremy_kJ Offline
      jeremy_k
      wrote on last edited by
      #2

      @SamGrant-Auterion said in QML XMLHttpRequest vs QNetworkAccessManager requests:

      Building a QT/QML application that issues GET and POST requests to a custom locally hosted service.

      If I examine the HTTP packets with WireShark, I see that when initiating the calls from QML/Javascript... the GET and POST packets are sent as 'Continuation'. With the POST, the JSON data is in a later packet. When checking the same packets when the calls are initiated from C++, the packets are NOT marked as 'Continuation', and the POST packet contains all the JSON data as intended.

      Unless this is an unusual server that violates the spirit of the protocol, the number of packets is irrelevant to correct operation. TCP delivers a stream of octets in sequence. The division between packets is traditionally not visible to applications.

      Wireshark C++ POST Packet:

      A single TCP packet likely provides inadequate information for this problem. Right click on the packet and select follow -> TCP stream or HTTP stream.

      Also, as stated higher up, if I set up a Q_INVOKABLE that calls the same QNetworkAccessManager function as above from QML/Javascript... I get the same result as if I were calling XMLHttpRequest directly.

      It sounds like there is an unintended conversion in the data being sent. Try examining the data passed to the Q_INVOKABLE both via javascript, and C++. Compare it to the data sent via the pure C++ implementation.

      Asking a question about code? http://eel.is/iso-c++/testcase/

      S 1 Reply Last reply
      0
      • jeremy_kJ jeremy_k

        @SamGrant-Auterion said in QML XMLHttpRequest vs QNetworkAccessManager requests:

        Building a QT/QML application that issues GET and POST requests to a custom locally hosted service.

        If I examine the HTTP packets with WireShark, I see that when initiating the calls from QML/Javascript... the GET and POST packets are sent as 'Continuation'. With the POST, the JSON data is in a later packet. When checking the same packets when the calls are initiated from C++, the packets are NOT marked as 'Continuation', and the POST packet contains all the JSON data as intended.

        Unless this is an unusual server that violates the spirit of the protocol, the number of packets is irrelevant to correct operation. TCP delivers a stream of octets in sequence. The division between packets is traditionally not visible to applications.

        Wireshark C++ POST Packet:

        A single TCP packet likely provides inadequate information for this problem. Right click on the packet and select follow -> TCP stream or HTTP stream.

        Also, as stated higher up, if I set up a Q_INVOKABLE that calls the same QNetworkAccessManager function as above from QML/Javascript... I get the same result as if I were calling XMLHttpRequest directly.

        It sounds like there is an unintended conversion in the data being sent. Try examining the data passed to the Q_INVOKABLE both via javascript, and C++. Compare it to the data sent via the pure C++ implementation.

        S Offline
        S Offline
        SamGrant - Auterion
        wrote on last edited by
        #3

        @jeremy_k Thanks for the feedback.

        I have already checked the JSON output from all three iterations, and it's the same.

        The more I work on this, the more I think it's the service that is not reading the packets correctly.

        S 1 Reply Last reply
        0
        • S SamGrant - Auterion

          @jeremy_k Thanks for the feedback.

          I have already checked the JSON output from all three iterations, and it's the same.

          The more I work on this, the more I think it's the service that is not reading the packets correctly.

          S Offline
          S Offline
          SamGrant - Auterion
          wrote on last edited by
          #4

          So... long story short. Issue was because of the TOKEN. When reading it into a variable via Javascript, the EOF markers (\n\r) were included in the string. Simply using a .replace() with a regex removed them and it works now.

          1 Reply Last reply
          2
          • S SamGrant - Auterion has marked this topic as solved on

          • Login

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