qtxmlhttprequestqmlqnetworkaccessmanager

QML XMLHttpRequest vs QNetworkAccessManager requests


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: enter image description here

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: enter image description here

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


Solution

  • 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.