Can't Successfully Login With QNetworkReply* (REST API)
-
Hi, I am trying to successfully receive a token so I can receive and edit data from a website (REST API) I control.
In order to do this, a header in the form ofheader = {"accept": "application/json", "Content-Type": "application/json"}
and data in the form of
datas= {"username": "admin", "password": "pass1234"}
must be passed thorough a post request in order to work. I have already accomplished this successfully to the website with Python code I have written here:
l = requests.post("http://coolwebsite.com:3245/login", data=json.dumps(datas), headers=header)
When I try to implement this in C++ thorough Qt using the code below, I receive nothing back in replyPost or postResponse. replyPost is shown in the debugger with a value of "". Any help or insight is appreciated!
//DATA QByteArray datas = "{\"username\":\"admin\",\"password\":\"pass1234\"}"; //Create Request QUrl serviceURL("http://coolwebsite.com:3245/login"); QNetworkRequest request(serviceURL); //HEADER request.setRawHeader("accept", "application/json"); request.setRawHeader("Content-Type", "application/json"); //Execute QNetworkAccessManager qnam; QNetworkReply* replyPost = qnam.post(request, datas); QByteArray postResponse = replyPost->readAll(); qDebug() << postResponse; qDebug() << qPrintable(postResponse);
Here is a screenshot of the variable explorer just after the last line executes :
-
@SGaist Thank you so much for the quick reply. I decided to write this:
connect(&qnam, SIGNAL(finished(QNetworkReply*)), this, SLOT(handleNetworkData(QNetworkReply*))); //ADDED //DATA QByteArray datas = "{\"username\":\"admin\",\"password\":\"pass1234\"}"; //Create Request QUrl serviceURL("http://coolwebsite.com:3245/login"); QNetworkRequest request(serviceURL); //HEADER request.setRawHeader("accept", "application/json"); request.setRawHeader("Content-Type", "application/json"); //Execute QNetworkAccessManager qnam; QNetworkReply* replyPost = qnam.post(request, datas); QByteArray postResponse = replyPost->readAll(); qDebug() << postResponse; qDebug() << qPrintable(postResponse);
and this respectively in the .h
public slots: void handleNetworkData(QNetworkReply*);
It now provides this error when attempting to run. I have already tried qmake:
moc_restWindow.obj:-1: error: LNK2019: unresolved external symbol "public: void __cdecl RestWindow::handleNetworkData(class QNetworkReply *)" (?handleNetworkData@RestWindow@@QEAAXPEAVQNetworkReply@@@Z) referenced in function "private: static void __cdecl RestWindow::qt_static_metacall(class QObject *,enum QMetaObject::Call,int,void * *)" (?qt_static_metacall@RestWindow@@CAXPEAVQObject@@W4Call@QMetaObject@@HPEAPEAX@Z)EDIT: Looks like the error might just be due to it not being able to see a moc_restWindow.obj, but this was never an issue before implementing the modifications above and nothing else.
-
Did you forget to add the
Q_OBJECT
macro in your class declaration ?
If so then do it and then for a re-run of qmake, if it's already there, for a re-run of qmake. -
Q_OBJECT is already placed in my .h:
#ifndef RESTWINDOW_H #define RESTWINDOW_H #include <QDialog> //including QDialog #include <QNetworkAccessManager> #include <QNetworkReply> #include "global.h" namespace Ui { class RestWindow; } class RestWindow : public QDialog { Q_OBJECT //here it was already placed public: explicit RestWindow(vendor *vendor, QWidget *parent = nullptr); ~RestWindow(); void checkDirectory(); QNetworkAccessManager qnam; vendor *m_vendor; QUrl url; QNetworkReply *reply; QFile *file; bool httpRequestAborted; long long totalBytesRead; QFile *openFileForWrite(const QString &fileName); QString *dir; QString *fileName; dataBase *dbase; public slots: void httpFinished(); void httpReadyRead(); void startRequest(const QUrl &requestedUrl); void slotAuthenticationRequired(QNetworkReply *, QAuthenticator *authenticator); void startDownload(); void cancelDownload(); void authenChanged(); void networkReplyProgress(qint64 bytesRead, qint64 totalBytes); void dataBaseChanged(); void handleNetworkData(QNetworkReply*); //added private: Ui::RestWindow *ui; }; #endif // REST_H
Is this the proper implementation of Q_OBJECT?
If so, what would the next step be to solve this error?Edit: I just reran qmake again successfully.
Edit2: It is also outputting a LNK1120 error:
Edit3: restWindow.cpp and .h are correctly mentioned in the .pro file
Edit4: It sees moc_restWindow.obj when I move the file from the debug folder to my Desktop. When I place it back it no longer sees it again.Edit5: If I comment out every modification I have made, and remove from .h what I added
void handleNetworkData(QNetworkReply*);
It works perfectly fine. When I uncomment the line above, the error returns. Is this a bug?
-
@surferbrain Have you implemented
handleNetworkData
in your .cpp? -
@surferbrain But instead of
QNetworkAccessManager::finished
, we usually connect theQNetworkReply::finished
signal.
I see you already have a slot namedhttpFinished
, which signal does it connect to and what does it do? -
@Bonnie @SGaist
Hi, I was able to switch around several things, along with a much better understanding of connect().void RestWindow::startRequest(const QUrl &requestedUrl) //after startDownload { url =requestedUrl; //should be url from json file //DATA QByteArray datas = "{\"username\":\"admin\",\"password\":\"pass1234\"}"; // Time for building your request QUrl loginURL("http://coolwebsite:1234/login"); QNetworkRequest request(loginURL); //HEADER request.setRawHeader("accept", "application/json"); request.setRawHeader("Content-Type", "application/json"); reply = qnam.post(request, datas); connect(reply, &QNetworkReply::finished, this, &RestWindow::postFinished); } void RestWindow::postFinished(){ QByteArray postResponse = reply->readAll(); qDebug() << postResponse; qDebug() << qPrintable(postResponse); }
httpFinished is the function I created to write the eventual get request response to a file. I can't even receive the correct credential back from logging in. I am focusing on trying to login as of now.
The post request hangs the code for about 10-15 seconds. After, slot postFinished is triggered. postResponse = reply->readAll() returns a value of "" as seen in the variable explorer. I should be seeing at the very least a token value.
Perhaps I am not placing the correct data where it is needed to be in QNetworkRequest request or in datas? Here is the curl command equivalent that is used to log on:
curl -X POST "http://coolwebsite:1234/login" -H "accept: application/json" -H "Content-Type: application/json" -d "{ \"username\": \"admin\", \"password\": \"pass1234\"}"
-
You can use wireshark to check the difference between the two request sent. Or something like https://requestbin.com
-
@SGaist Hey! Just ran the above code (with qnam.post() inside the startRequest()) and no signal reaches the pipedream.net I created. My Python code reaches it just fine. Is there something fundamentally wrong with my code that I have not considered?
Edit: Just found that it looks like it is showing:
qt.network.ssl: QSslSocket::connectToHostEncrypted: TLS initialization failed
QIODevice::read (QNetworkReplyHttpImpl): device not open
This is strange as I already downloaded and modified the PATH for the Toolkit I use, but now the PATH variable looks unmodified.I was using openSSL1.0.2p before, but now when I run
qDebug() << QSslSocket::sslLibraryBuildVersionString();
at the end of my code it displays "OpenSSL 1.1.1d 10 Sep 2019"
Was there an update to Qt recently that could have changed this in the past few days? It's showing the same issue with another qt project that used to work about a week ago. -
Not in the past few days, IIRC, OpenSSL 1.1 support started with 5.10 and the ore-built package switched to it during the 5.12 release cycle.