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:
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:
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 -
@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.
-
@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.
-
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.
-