I am developing an app on BB 10 based on C++ where I need to send HTTP post requests to the server and retrieve some JSON data. Are there some framework classes that help you send HTTP post requests to the server? Any links to code etc.? Thanks.
I can't remember which sample app I found this code in, but this worked for what I needed in my app.
Add the following in c++
header file (.hpp)
public:
Q_INVOKABLE void doNetworkRequest(QString url);
signals:
void networkReply(const QVariantMap &data);
void networkError();
private Q_SLOTS:
void handleNetworkData(QNetworkReply *reply);
private:
QNetworkAccessManager networkManager;
Then in add this in your main file (.cpp)
this goes inside the main app function
// Hook this signal so we can respond to network replies
connect(&networkManager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(handleNetworkData(QNetworkReply *)));
add these functions:
void Top12Wines::doNetworkRequest(QString url)
{
qDebug() << "Request URL " << url;
QUrl qurl = url;
networkManager.get(QNetworkRequest(qurl));
}
void Top12Wines::handleNetworkData(QNetworkReply *reply)
{
if (!reply->error()) {
qDebug() << "Got network data";
// Let's get ALL the data
const QByteArray response(reply->readAll());
JsonDataAccess jda;
QVariantMap results = jda.loadFromBuffer(response).toMap();
emit networkReply(results);
} else {
qDebug() << "Got network error";
emit networkError();
}
// Cleanup
reply->deleteLater();
}
Then in your QML you can access it like so:
_App.networkReply.connect(checkVersion); //
_App.networkError.connect(checkVersionError);
_App.doNetworkRequest("http://myserver/version.json");
function checkVersion(data)
{
_App.networkReply.disconnect(checkVersion); //disconnect links after retrieving data
_App.networkError.disconnect(checkVersionError);
var newVersion = data.version;
}
function checkVersionError()
{
_App.networkReply.disconnect(checkVersion); //disconnect links after retrieving data
_App.networkError.disconnect(checkVersionError);
//do something to alert user that an error occurred.
}
Related
How do I read the data from a QNetworkReply response from a specific URL before QWebPage does? but when the finished() signal is emited the reply is read already by QWebPage, so connect readyRead() or call reply->readAll() return nothing. I tried overload acceptNavigationRequest() method in my own QWebPage class, something like this:
bool webPage::acceptNavigationRequest(QWebFrame *frame, const QNetworkRequest &request, QWebPage::NavigationType type)
{
//qDebug() << "filename = " << request.rawHeader("content-disposition");
if(request.url().path() == QStringLiteral("download.php"))
{
QNetworkReply *reply = networkAccessManager()->get(request);
QFile file;
file.setFileName(filename);
if(!file.open(QIODevice::ReadWrite))
{
/* handle error */
}
file.write(reply->readAll());
file.close();
return false;
}
But I couldn't manage to reply work... the returned reply is invalid (don't even return a http status code, I know it means the http request sent is invalid but i don't know why).
Different approachs to solve this are welcome!
Using the finished slot with a lambda expression, you can do this: -
QNetworkReply* reply = networkAccessManager()->get(request);
connect(reply, &QNetworkReply::finished, [=]() {
if(reply->error() == QNetworkReply::NoError)
{
QByteArray response = reply->readAll();
// do something with the data...
}
else // handle error
{
qDebug(pReply->errorString());
}
});
I have written a test class that I'm using to learn more about QNetworkAccessManager and its functionality related to FTP uploading. I'm trying to upload files from my Raspberry Pi to my Windows PC through FTP and this works well when I just want to upload a single file. However, I want to transmit multiple files at once; the same way FileZilla does this when you drag a folder between client and host; it starts multiple up/downloads instead of one after the other sequentially. Below are my ftp_test.h and ftp_test.cpp files. If I provide upload() with a list of filenames, it will for each name in this list, do a put request on the server. However, only the first file gets uploaded, the second, third, fourth. etc. get ignored.
class ftp_test: public QObject
{
Q_OBJECT
public:
ftp_test (QObject *p = 0): QObject(p) { }
void upload(QString video_directory, std::vector<QString> filename);
public slots:
void uploadProgress(qint64 bytesSent, qint64 bytesTotal);
void uploadDone();
private:
QNetworkAccessManager nam;
QFile *data;
QNetworkReply *reply;
QEventLoop loop;
};
And my ftp_test.cpp
void ftp_test::upload(QString video_directory, std::vector<QString> filename)
{
for(int i = 0; i < filename.size(); i++)
{
QUrl url("ftp://xx.xx.xx.xxx:xxxxx/" + filename[i]);
url.setUserName("pi");
if(QFile::exists(video_directory + filename[i]))
{
data = new QFile(video_directory + filename[i], this);
if (data->open(QIODevice::ReadOnly))
{
reply = nam.put(QNetworkRequest(url), data);
connect(reply, SIGNAL(uploadProgress(qint64, qint64)), SLOT(uploadProgress(qint64, qint64)));
connect(reply, SIGNAL(finished()), SLOT(uploadDone()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(someError(QNetworkReply::NetworkError)));
}
else
{
return;
}
}
else
{
qDebug() << "Oops";
return;
}
}
loop.exec();
}
void ftp_test::uploadProgress(qint64 bytesSent, qint64 bytesTotal)
{
qDebug() << "Uploaded" << bytesSent << "of" << bytesTotal;
}
void ftp_test::uploadDone()
{
qDebug() << "Finished" << reply->error();
data->deleteLater();
reply->deleteLater();
reply = 0;
loop.quit();
}
I thought about making multiple threads for this to work, but before I delve into that, maybe there is something I'm missing.
I'm aware that it will stop uploading after the first upload was succesful, but it doesn't matter because I'm still not seeing parallel uploads.
Is this the way it's supposed to work? How do I achieve concurrent transfer of files instead of sequential?
I'm fairly new to C++ (though I have some experience with C) as well as QT. I'm trying to make a program that POSTs to a website when the user clicks a button, but whenever I try to access QNetworkManager I get a memory access error.
The code for my request object is as follows (trimmed slightly to show the important bits):
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include "cJSON.h"
class unifiedRequests: public QObject {
Q_OBJECT
public:
// Members
QString access_token = "";
bool admin = false;
// Methods
explicit unifiedRequests(QObject *parent=0);
QNetworkReply* login_request(QString *email, QString *password);
signals:
public slots:
void login_complete(QNetworkReply *reply);
void sslErrorHandler(QNetworkReply*, const QList<QSslError> & );
private:
QNetworkRequest make_headers(QByteArray endpoint);
QNetworkRequest make_headers(QByteArray endpoint, QByteArray *access_token);
};
QNetworkRequest unifiedRequests::make_headers(QByteArray endpoint) {
QString url = endpoint.prepend("https://dali.vpt.co.uk");
QNetworkRequest request = QNetworkRequest(url);
qDebug() << "Setting Headers";
request.setRawHeader("User-Agent", "Desktop Client Debug");
request.setRawHeader("Content-Type", "application/json");
qDebug() << "Set headers successfully.";
return request;
}
void unifiedRequests::sslErrorHandler
(QNetworkReply* reply, const QList<QSslError> & errors) {
qDebug() << "Ignoring SSL Errors";
};
QNetworkReply* unifiedRequests::login_request
(QString *email, QString *password) {
QNetworkRequest request = make_headers("/api/auth");
qDebug() << "Making JSON";
cJSON *login_json; //The body of the request
login_json = cJSON_CreateObject();
cJSON_AddStringToObject(login_json, "email", email->toUtf8());
cJSON_AddStringToObject(login_json, "password", password->toUtf8());
qDebug() << "Made JSON: ";
qDebug() << cJSON_Print(login_json);
QNetworkAccessManager *manager = new QNetworkAccessManager;
//The object we use to send the request and receive the reply
qDebug() << "Turning off SSL";
connect(manager,
SIGNAL(sslErrors(QNetworkReply*, const QList<QSslError> & )),
this,
SLOT(sslErrorHandler(QNetworkReply*, const QList<QSslError> & )));
qDebug() << "POSTing login.";
QNetworkReply *reply = manager->post(request, cJSON_Print(login_json));
qDebug() << "Connecting signal to slot.";
QAbstractSocket::connect(manager, SIGNAL(finished(QNetworkReply * )),
this, SLOT(login_complete(QNetworkReply * )));
cJSON_Delete(login_json);
return reply;
}
I'm creating the unifiedRequests object by calling:
unifiedRequests requestObj;
in a different file. It crashes out on the line where I try to turn off SSL (we're using a self-signed certificate, so I need to do this in order to make the request). Any thoughts?
Thank you!
You create the unifiedRequests object by calling "unifiedRequests requestObj;", this object will be deleted when the variable "requestObj" goes out of scope.
So, when the signal will be received, the object will be already destroyed.
Try to create your unifiedRequests object by calling "unifiedRequests* requestObj = new unifiedRequests();".
Of course, you need to call "delete requestObj;" somewhere to destroy this object. Where and when depend on your application (when you don't need this object anymore).
To understand the difference, look at here : http://www.tutorialspoint.com/cplusplus/cpp_dynamic_memory.htm
Or google for "C++ heap / stack / dynamic allocation"
I need to get a json file from an url, fill it in a QtNetworkReply *reply and send reply in a connected fonction to convert it in QbyteArray to pars my Json response.
But when i go in my connected function, i cant fill QByteArray with that reply (always empty)
Here's my code :
int main(int ac, char *av[])
{
Borne borne(ac, av);
reply myReply;
QNetworkAccessManager networkManager;
QUrl url("http://vps202498.ovh.net:8080/ws/rest/v.1/stores/categories/150/products");
QNetworkRequest request;
request.setUrl(url);
myReply._reply = networkManager.get(request);
QObject::connect(myReply._reply, SIGNAL(finished()), &myReply, SLOT(fonction()));
myReply._reply->finished();
exit(1);
if (borne.initialize() == false)
return (false);
return (borne._app->exec());
}
And here's my connected function :
IProduct *reply::fonction()
{
QByteArray List;
std::cout << "connected" << std::endl;
List = _reply->readAll();
if (List.isNull())
exit(6);
return (NULL);
}
My .H :
class reply : public QObject
{
Q_OBJECT
public:
reply() {};
~reply() {};
QNetworkReply *_reply;
public slots:
IProduct *fonction();
private :
};
I cant std::cout "connected", but always quit with error log '6'.
I dont really know where am i doing mistake (Iam used to C, not Cpp), i've read all the man of Qt about it, and cant figure what going wrong.
Any ideas?
Thank you and apologize for weak skill and english
You call the finish() function manually immediately after creation of the request. In that moment the request is not even started, so there is nothing to read from _reply->readAll(). The reply finished signal should be called by the even loop after calling application exec().
Remove lines:
myReply._reply->finished();
exit(1);
The request will be processed asyncronously in the event loop.
Other issues:
the slot reply::fonction() does not need any retrun value;
the event loop may be not started because of (borne.initialize() == false).
Qt Creator is used as the ide for this small app that is being developed
I am attempting to use QNetworkAccessManager to retrieve some information from a website. After the request is 'posted' to the web, the finished() signal is triggered, however the pointer that is passed to the finishedSlot() function does not appear to be pointing to an instantiated object, it is just address of the ponter. The code for the button click that starts the request and the code for the finishedSlot() method is shown below.
In the watch window, I would have expected to see a triangle next to 'reply' that when expaned would show all the data member of QNetworkReply object. Instead it has a single value of #0x80c770 which looks like the pointer address.
I'd appreciate input from anyone who can help me to understand why my pointer doesn't appeart to be pointing the the QNetworkReply object.
void MainWindow::on_btnGetOAuthToken_clicked()
{
QUrl serviceUrl("https://api.ProPhotoWebsite.com/services/oauth/authorize.mg");
QUrl postData;
postData.addQueryItem("method", "ProPhotoWebsite.auth.getRequestToken");
postData.addQueryItem("oauth_consumer_key", "AAAAAAAAAAAAAAAAAAAAAAAA"); //example key
postData.addQueryItem("oauth_nonce",QUuid::createUuid().toString());
postData.addQueryItem("oauth_signature_method","PLAINTEXT");
postData.addQueryItem("oauth_signature","999999999999999999999999999"); //example
postData.addQueryItem("oauth_timestamp", QString::number(QDateTime::currentMSecsSinceEpoch()/1000));
postData.addQueryItem("oauth_version","1.0");
//...
QNetworkRequest request(serviceUrl);
request.setHeader(QNetworkRequest::ContentTypeHeader,
"application/x-www-form-urlencoded");
// Call the webservice
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
connect(nam, SIGNAL(finished(QNetworkReply*)),
SLOT(finishedSlot(QNetworkReply*)));
nam->post(request,postData.encodedQuery());
}
void MainWindow::finishedSlot(QNetworkReply *reply)
{
// Reading attributes of the reply
// e.g. the HTTP status code
QVariant statusCodeV =
reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
// Or the target URL if it was a redirect:
QVariant redirectionTargetUrl =
reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
// see CS001432 on how to handle this
// no error received?
if (reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll(); // bytes
QString string(bytes); // string
ui->lblWarning->setText(string);
}
else
{
// handle errors here
}
// need to dispose reply
delete reply;
}