How to send a POST request in Qt with the JSON body
Asked Answered
H

2

5

I'm trying to send a POST request from Qt where the body is in JSON format. Firstly I'm asserting that the request works in curl:

curl -i -H "Content-Type: application/json" -d '{"key1": "value1", "key2": "value2"}' -X POST http://myserver.com/api

That works OK, I'm receiving back the expected response from the server. The same works in Python. Now I need to send this request from C++/Qt:

QNetworkAccessManager *mgr = new QNetworkAccessManager(this);
QHttpMultiPart *httpMultiPart = new QHttpMultiPart(mgr);
QHttpPart *httpPart = new QHttpPart();
httpPart->setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
httpPart->setBody("{\"key1\":\"value1\", \"key2\":\"value2\"}");

httpMultiPart->append(*httpPart);

QNetworkReply *reply = mgr->post(QNetworkRequest(QUrl("http://myserver.com/api")), httpMultiPart);
QObject::connect(reply, &QNetworkReply::finished, [=]()
        {
            QString err = reply->errorString();
            QString contents = QString::fromUtf8(reply->readAll());
        });

Now I'm getting an error where the errorString returns: `

"Error downloading http://myserver.com/api - server replied: Unsupported Media Type"`

What can be the reason? How should I send the POST request like the one that I'm sending with curl?

Hawser answered 7/2, 2020 at 5:29 Comment(0)
X
18

QHttpMultiPart is used to send MIME multipart message but in this case it is not required to send that type of information. Instead, you should use QJsonDocument to create the json and convert it to QByteArray:

QNetworkAccessManager *mgr = new QNetworkAccessManager(this);
const QUrl url(QStringLiteral("http://myserver.com/api"));
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

QJsonObject obj;
obj["key1"] = "value1";
obj["key2"] = "value2";
QJsonDocument doc(obj);
QByteArray data = doc.toJson();
// or
// QByteArray data("{\"key1\":\"value1\",\"key2\":\"value2\"}");
QNetworkReply *reply = mgr->post(request, data);

QObject::connect(reply, &QNetworkReply::finished, [=](){
    if(reply->error() == QNetworkReply::NoError){
        QString contents = QString::fromUtf8(reply->readAll());
        qDebug() << contents;
    }
    else{
        QString err = reply->errorString();
        qDebug() << err;
    }
    reply->deleteLater();
});
Xantho answered 7/2, 2020 at 5:53 Comment(4)
That worked, thank you. The follow up question: is there a way to get a string presentation of the request that is about to be sent? That would help to solve the issues like the one I posted here.Hawser
@DmitryKuzminov Do you mean the raw data that is sent to the server? In general if you want to analyze that type of data then you should use tools like wiresharkXantho
The wireshark would be an overkill. In theory if QNetworkRequest internally constructs a string to be used as an HTTP request, there may be a way to view that string directly.Hawser
@DmitryKuzminov No, your theory is incorrect: QNetworkRequest does not build anything, but only stores information such as headers and url, and it builds the HTTP request is QNetworkAccessManager (in the private API).Xantho
K
1
QNetworkAccessManager *mgr = new QNetworkAccessManager(this);

QUrl url = QUrl("http://myserver.com/api");

QJsonObject param;
param.insert("key1", QJsonValue::fromVariant("value1"));
param.insert("key2", QJsonValue::fromVariant("value2"));

QNetworkRequest request(url);

request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

QNetworkReply* reply = mgr->post(request, QJsonDocument(param).toJson(QJsonDocument::Compact));

/*Реализуем ожидание конца загрузки с таймаутом*/
QTimer timer;
timer.setSingleShot(true);

QEventLoop loop;
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
timer.start(10000);   // 10 secs. timeout
loop.exec();

if(timer.isActive())
{
    timer.stop();
    if(reply->error() == QNetworkReply::NoError)
    {
        // Success
        QByteArray buffer = reply->readAll();

        qDebug()<<buffer;
    }
    else
    {
        // handle error
        QString error = reply->errorString();
        qDebug()<< "reply->errorString() " << error;
    }
}
else
{
    disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    reply->abort();
}

reply->deleteLater();
Kvass answered 23/12, 2020 at 23:20 Comment(1)
your answer may solve the problem, but it would be better if you provide some explanation along with it.Deflect

© 2022 - 2024 — McMap. All rights reserved.