This is the task: i catch signal from
QNetworkAccessManager* manager= new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(parse_data_request(QNetworkReply*)));
connect(manager, &QNetworkAccessManager::finished, manager,
&QNetworkAccessManager::deleteLater,Qt::QueuedConnection);
And i want send to slot parse_data_request int variable with QNetworkReply* like this:
QNetworkAccessManager* manager= new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*,int)), this, SLOT(parse_data_request(QNetworkReply*,int)));
connect(manager, &QNetworkAccessManager::finished, manager,
&QNetworkAccessManager::deleteLater,Qt::QueuedConnection);
How can i do it?
If you're using Qt5 (which you appear to be) then you can use a lambda as the target of the connection...
int request_id = ...;
QNetworkAccessManager* manager= new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished, this,
[this, request_id](QNetworkReply *reply)
{
parse_data_request(reply, request_id);
});
connect(manager, &QNetworkAccessManager::finished, manager, &QNetworkAccessManager::deleteLater,Qt::QueuedConnection);
Related
I'm using the code below to make a http request:
QNetworkReply* ApiRequest::req(QString url, QString method, QByteArray data) {
QByteArray request_method = method.toUtf8();
QNetworkAccessManager* manager = new QNetworkAccessManager();
QNetworkRequest request("http://127.0.0.1:9090" + url);
request.setRawHeader("Content-Type", "application/json");
QNetworkReply* reply = manager->sendCustomRequest(request, request_method, data);
return reply;
}
void ApiRequest::requestConfig()
{
NetworkReply* reply = req("/configs",
"GET",
"");
}
The Remote server did execute the request and reply a 204 code.
I have used wireshark to capture and make sure it had reply a 204 No Content.
However, the output there is QVariant(Invalid), the toInt output is 0.
I tried to change PUT to GET but it still not working.
You are analyzing the state even when the request has not been made so it is valid that the result is null, what you should do is analyze it when the finished signal is emitted:
QNetworkReply* reply = mg->sendCustomRequest(request, "PUT", "....some json....");
connec(reply, &QNetworkReply::finished, [reply](){
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
});
Update:
connec(mg, &QNetworkAccessManager::finished, [](QNetworkReply *reply){
qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
});
Update 2:
Is there a way to return that reply when it is finished?
Yes, use a QEventLoop, but in general it is a bad design since you should use signals and slots to notify you of the changes.
QNetworkReply* ApiRequest::req(const QString & url, const QString & method, const QByteArray & data) {
QByteArray request_method = method.toUtf8();
QNetworkAccessManager manager;
QNetworkRequest request("http://127.0.0.1:9090" + url);
request.setRawHeader("Content-Type", "application/json");
QNetworkReply* reply = manager.sendCustomRequest(request, request_method, data);
QEventLoop loop;
connec(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
loop.exec();
return reply;
}
// ...
void ApiRequest::requestConfig()
{
QNetworkReply* reply = req("/configs", "GET", "");
// ...
reply->deleteLater();
}
You can include QtNetworkReply and QEventLoop classes and use signal/slot mechanism.
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
QUrl resource(url);
QNetworkRequest request(resource);
QNetworkReply *reply = manager->get(request);
QEventLoop loop;
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QJsonObject jsonObject = QJsonDocument::fromJson(reply->readAll()).object();
This code downloads a video, but for some reason does not work
globals.h
QString videoDirectLink = "";
mainwindow.cpp
#include "globals.h"
void MainWindow::readOutput() {
QByteArray outData = myProcess->readAllStandardOutput(); // read from CMD
videoDirectLink = outData; // videoDirectLink Contains https://media08.vbox7.com/s/91/91f4c651car96dafe736.mp4
if (videoDirectLink.contains("https")) {
// SSL downloading
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
connect(manager2, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
QNetworkRequest *req = new QNetworkRequest();
req->setUrl(QUrl(videoDirectLink)); //videoDirectLink
QSslConfiguration configSsl = QSslConfiguration::defaultConfiguration();
configSsl.setProtocol(QSsl::AnyProtocol);
req->setSslConfiguration(configSsl);
connect(manager2->get(*req), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
}
If changes req->setUrl(QUrl(videoDirectLink));
to req->setUrl(QUrl("https://media08.vbox7.com/s/91/91f4c651car96dafe736.mp4"));
or
QString n ="https://media08.vbox7.com/s/91/91f4c651car96dafe736.mp4";
req->setUrl(QUrl(n));
everything works
This is worked code for download without SSL. The principle is the same
globals.h
QString videoDirectLink = "";
mainwindow.cpp
#include "globals.h"
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
// start downloading
connect(manager, SIGNAL(finished(QNetworkReply*)),
this, SLOT(downloadFinished(QNetworkReply*)));
QString target = videoDirectLink;
QUrl url = QUrl::fromEncoded(target.toLocal8Bit());
connect(manager->get(QNetworkRequest(url)), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
I tried to add encoding, but that is not the problem.
other suggestions ?
// NOT WORKING
void MainWindow::readOutput() {
QString outData = myProcess->readAllStandardOutput(); // URL -> https://www.vbox7.com/play:91f4c651ca
videoDirectLink = outData; // videoDirectLink -> https://media28.vbox7.com/s/91/91f4c651car96dafe736.mp4
if (videoDirectLink.contains("https")) {
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
connect(manager2, SIGNAL(finished(QNetworkReply*)), this, SLOT(downloadFinished(QNetworkReply*)));
QNetworkRequest *req = new QNetworkRequest();
req->setUrl(QUrl(videoDirectLink)); //videoDirectLink
connect(manager2->get(*req), SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(downloadProgress(qint64,qint64)));
QMessageBox::information(this,"SSL downloading",videoDirectLink,"ok"); // displays https://media28.vbox7.com/s/91/91f4c651car96dafe736.mp4
}
}
I'm trying to use QsignalMapper to pass my String to img_loaded function, on finished SIGNAL. But I can not get any result, please help.
QString mystring = "value";
QNetworkAccessManager *m_netwManager = new QNetworkAccessManager(this);
QUrl url("http://images.gs-cdn.net/static/albums/80_9299765.jpg");
QNetworkRequest request(url);
connect(m_netwManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(img_loaded(QNetworkReply*)));
void MainWindow::img_loaded(QNetworkReply *rep){
//Handle my String here
}
If you want to supply additional parameters to identify networkReply try this:
void myClass::downloadMedia(QString url, int mediaType, int messageID)
{
bool connect_result;
QNetworkAccessManager *manager2 = new QNetworkAccessManager(this);
connect_result = connect(manager2, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onMediaDownloaded(QNetworkReply*)));
Q_ASSERT(connect_result);
QNetworkReply* reply = manager2->get(QNetworkRequest(url));
// Here are the additional parameters
reply->setProperty("mediaType", mediaType);
reply->setProperty("messageID", messageID);
}
And there is the slot
void myClass::onMediaDownloaded(QNetworkReply *reply)
{
int mediaType = reply->property("mediaType").toInt();
int messageID = reply->property("messageID").toInt();
switch (mediaType) {
// Handle different media types
.....
}
}
You cannot use QSignalMapper in this case. QSignalMapper allows to specify additional data separately for each sender. However, you have only one sender (QNetworkAccessManager object). You could use QNetworkReply's signals (as #derkode suggested) and use QSignalMapper on them, but this is an over-complication.
QNetworkAccessManager already sends QNetworkReply* object as a signal parameter. That is quite similar to QSignalMapper functionality. We only need to attach additional data to each reply. For example, you can create such private field in your class:
QHash<QNetworkReply*, QString> data_storage;
Replace QString with the type of your additional data (QVariant, int, or else). Add data when you make a request:
QNetworkReply* reply = m_netwManager->get(...);
data_storage[reply] = my_data;
Get that data when the request is finished and clean up:
void MainWindow::img_loaded(QNetworkReply *reply) {
QString my_data = data_storage[reply];
data_storage.remove(reply);
//... read reply and use data
}
Try so:
QString mystring = "value";
QNetworkRequest request;
request.setUrl(QUrl("http://images.gs-cdn.net/static/albums/80_9299765.jpg");
QNetworkAccessManager m_networkManager = new QNetworkAccessManager(this);
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, SIGNAL(finished()), this, SLOT(img_loaded()));
void MainWindow::img_loaded() {
//For example
QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender());
QByteArray data = reply->readAll();
}
I want to POST some info to a php and GET the result from that php.
My POST should look like: www.sample.com/test.php?un=user&pass=123345
I am trying all variants with no success:
m_NetworkAccessMNGR = new QNetworkAccessManager(this);
connect(m_NetworkAccessMNGR, SIGNAL(finished(QNetworkReply*)),
this,SLOT(slotFinishRequest(QNetworkReply*)));
QNetworkRequest networkRequest;
networkRequest.setUrl(QUrl("http://www.sample.com/test.php?un=user&pass=123345"));
QNetworkReply *reply = m_NetworkAccessMNGR->get(networkRequest);
connect(reply, SIGNAL(readyRead()),
this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(finished()),
this, SLOT(slotOnRequestCompleted()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotOnRequestError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(slotSslErrors(QList<QSslError>)));
The code doesn't execute any of these slots.
Does anybody has any ideea on what is the problem?Thank you
Do you have an event loop somewhere else in your code?
If not, try this :
QEventLoop loop;
m_NetworkAccessMNGR = new QNetworkAccessManager(this);
QNetworkRequest networkRequest;
networkRequest.setUrl(QUrl("http://www.sample.com/test.php?un=user&pass=123345"));
QNetworkReply *reply = m_NetworkAccessMNGR->get(networkRequest);
connect(reply, SIGNAL(readyRead()),
this, SLOT(slotReadyRead()));
connect(reply, SIGNAL(finished()),
this, SLOT(slotOnRequestCompleted()));
connect(reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(slotOnRequestError(QNetworkReply::NetworkError)));
connect(reply, SIGNAL(sslErrors(QList<QSslError>)),
this, SLOT(slotSslErrors(QList<QSslError>)));
connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
Does that work any better?
I would like to test an asynchronous request to a webserver. For that purpose I'm creating a simple unittest to quickly try a few lines of code:
void AsynchronousCall::testGet()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QUrl url("http://myownhttpserver.org");
QNetworkRequest req(url);
this->connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(reqFinished(QNetworkReply *)));
QNetworkReply *rep = nam->get(req);
}
void AsynchronousCall::reqFinished(QNetworkReply *rep)
{
qDebug() << rep->readAll();
qDebug() << "finshed";
}
The problem is that reqFinished() is never reached.
If I had a simple QEventLoop and and a loop.exec() just after the nam->get(req); the request is executed.
Any hint ? Do I have to use a loop.exec() in my every unittests ?
If you want to test asynchronous behavior, you have to use QEventLoop or other class with similar functionality. I suggest you write helper method like this:
bool waitForSignal(QObject *sender, const char *signal, int timeout = 1000) {
QEventLoop loop;
QTimer timer;
timer.setInterval(timeout);
timer.setSingleShot(true);
loop.connect(sender, signal, SLOT(quit()));
loop.connect(&timer, SIGNAL(timeout()), SLOT(quit()));
timer.start();
loop.exec();
return timer.isActive();
}
Then you can use it in your unit tests like this:
void AsynchronousCall::testGet()
{
QNetworkAccessManager *nam = new QNetworkAccessManager(this);
QUrl url("http://myownhttpserver.org");
QNetworkRequest req(url);
this->connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(reqFinished(QNetworkReply *)));
QNetworkReply *rep = nam->get(req);
QVERIFY(waitForSignal(nam, SIGNAL(finished(QNetworkReply*)), 5000));
}
There are also other issues with your test:
Tests that depend on network connection shouldn't be unit tests. You want your unit tests to be blazing fast, which is impossible to achieve with network connections.
Your test doesn't really test anything: it just puts some info to debug console. You should define expectations and verify them using QVERIFY and QCOMPARE macros.
QTest sucks IMHO. If you're creating test base from scratch, start using gtest + gmock instead.