If I do a HTTP request (an example from Binance docs) with CURL from the command line
curl -H "X-MBX-APIKEY: vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A" -X POST 'https://api.binance.com/api/v3/order/test' -d 'symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559&signature=c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71'
I get:
{"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
but if I do
QNetworkRequest request;
request.setRawHeader(QByteArray("X-MBX-APIKEY"), QString("vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A").toUtf8());
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/x-www-form-urlencoded"));
request.setUrl(QUrl("https://api.binance.com/api/v3/order/test"));
QByteArray postData = "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559&signature=c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71";
QNetworkReply* reply = m_nm.post(request, postData);
QObject::connect(reply, &QNetworkReply::finished, [this, reply, url, func]()
{
if (reply->error())
{
qDebug() << "Error: " << reply->error() << ", Message: " << reply->errorString();
});
}
else
{
const QString answer = reply->readAll();
func(answer);
}
//Ensure it is deleted after this handler is called, but not before.
//reply->deleteLater();
delete reply;
});
I get an error reply with the message Error: 204, Message: Host requires authentication
.
With other API key I get Bad request
with QNetworkReply::ProtocolInvalidOperationError
.
What is the difference?
EDIT1:
The request successes with
request.setUrl(QUrl("https://httpbin.org/post"));
and the same post data, for example.
EDIT2:
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-GB,*"
but it is not they.
The HTTP 401 error code indicates that the request has not been executed because it lacks valid authentication credentials for the requested resource, and that causes Qt to create the error QNetworkReply::AuthenticationRequiredError, and in addition to that, information about the cause of the error in the response body. Therefore, even when there is an error, you must check the data.
MWE:
#include <QtNetwork>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QNetworkAccessManager m_nm;
QNetworkRequest request;
request.setRawHeader(QByteArray("X-MBX-APIKEY"), QString("vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A").toUtf8());
request.setHeader(QNetworkRequest::ContentTypeHeader, QString("application/x-www-form-urlencoded"));
request.setUrl(QUrl("https://api.binance.com/api/v3/order/test"));
QByteArray postData = "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559&signature=c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71";
QNetworkReply* reply = m_nm.post(request, postData);
QObject::connect(reply, &QNetworkReply::finished, [reply]()
{
const QString body = reply->readAll();
if (reply->error() == QNetworkReply::AuthenticationRequiredError){
qDebug() << "Error: " << reply->error() <<
", Message: " << reply->errorString() <<
", Code: " << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() <<
", Description: " << body;
}
else if (reply->error() != QNetworkReply::NoError){
qDebug() << body;
}
reply->deleteLater();
QTimer::singleShot(1000, &QCoreApplication::quit);
});
return a.exec();
}
Output:
Error: QNetworkReply::AuthenticationRequiredError , Message: "Host requires authentication" , Code: 401 , Description: "{\"code\":-2015,\"msg\":\"Invalid API-key, IP, or permissions for action.\"}"