使用 QNetworkManager 在 QT 中设计多个嵌套 GET/POST 的最佳方法
Best way to design multple and nested GET/POST in QT with QNetworkManager
我的疑问是关于实现多个嵌套 GET/POST 请求的软件的正确设计。
假设您必须 运行 需要一个 GET 和一个 POST 的 login() 函数,然后是需要两个 GET 的 retrieveXYZ()(依此类推,可扩展)。
我想这样做的方式就像
mainwindow.cpp
//code
login();
retrieveXYZ();
//code
Mainwindow::login(){
//code
connect(nam, SIGNAL(finished()), this, SLOT(onGetLoginFinished()));
nam->get(...);
}
Mainwindow::onGetLoginFinished(){
//do stuff
connect(nam, SIGNAL(finished()), this, SLOT(onPostLoginFinished()));
nam->post(...);
}
Mainwindow::onPostLoginFinished(){
//do stuff
}
Mainwindow::retrieveXYZ(){
//code
connect(nam, SIGNAL(finished()), this, SLOT(onGet1RetrieveFinished()));
nam->get();
//code
}
Mainwindow::onGet1RetrieveXYZFinished(){
//do stuff
connect(nam, SIGNAL(finished()), this, SLOT(onGet2RetrieveFinished()));
nam->get();
}
或者我应该使用 QSignalMapper 之类的东西吗?
最 correct/efficient 的方法是什么?我见过有人使用 sender() cast 但我不明白这一点。
基本上我想检索特定的回复 finished() 信号而不是一般的(或 qnam 的)
这个方法可能有用,但对我来说不是很好和干净
这是我们能得到的最好的吗?
将连接方法移动到回复?
我得到了类似的东西:
struct RequestResult {
int httpCode;
QByteArray content;
};
RequestResult
ExecuteRequest(const std::function<QNetworkReply*(QNetworkAccessManager&)>& action,
const std::chrono::milliseconds& timeOut)
{
QEventLoop eLoop;
QTimer timeOutTimer;
QNetworkAccessManager nam;
QObject::connect(&timeOutTimer, &QTimer::timeout, &eLoop, &QEventLoop::quit);
QObject::connect(&nam, &QNetworkAccessManager::finished, &eLoop, &QEventLoop::quit);
timeOutTimer.setSingleShot(true);
timeOutTimer.setInterval(timeOut.count());
timeOutTimer.start();
auto resetTimeOut = [&timeOutTimer]() { timeOutTimer.start(); };
QNetworkReply* reply = action(nam);
QObject::connect(reply, &QNetworkReply::uploadProgress, resetTimeOut);
QObject::connect(reply, &QNetworkReply::downloadProgress, resetTimeOut);
eLoop.exec();
if (!timeOutTimer.isActive())
{
throw std::runtime_error("Time out"); // Probably custom exception
}
const int httpStatus
= reply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute).toInt();
auto content = TakeContent(*reply); // reply->readAll and decompression
return RequestResult{httpStatus, content};
}
然后 get/delete/post/.. 的功能类似于
auto RequestGet(const QNetworkRequest& request) {
return ExecuteRequest([&](QNetworkAccessManager& nam) { return nam.get(request); },
timeOut);
}
auto RequestDelete(const QNetworkRequest& request) {
return ExecuteRequest([&](QNetworkAccessManager& nam) {
return nam.deleteResource(request);
},
timeOut);
}
auto RequestPost(const QNetworkRequest& request, QHttpMultiPart& multiPart)
{
return ExecuteRequest([&](QNetworkAccessManager& nam) {
return nam.post(request, &multiPart);
},
timeOut);
}
然后,对于你的代码,我会做类似的事情
Mainwindow::login()
{
const auto getRes = RequestGet(..);
// ...
const auto postRes = RequestPost(..);
// ...
}
如果你不想阻塞调用,你可以使用 thread 和 future。
我的疑问是关于实现多个嵌套 GET/POST 请求的软件的正确设计。
假设您必须 运行 需要一个 GET 和一个 POST 的 login() 函数,然后是需要两个 GET 的 retrieveXYZ()(依此类推,可扩展)。
我想这样做的方式就像
mainwindow.cpp
//code
login();
retrieveXYZ();
//code
Mainwindow::login(){
//code
connect(nam, SIGNAL(finished()), this, SLOT(onGetLoginFinished()));
nam->get(...);
}
Mainwindow::onGetLoginFinished(){
//do stuff
connect(nam, SIGNAL(finished()), this, SLOT(onPostLoginFinished()));
nam->post(...);
}
Mainwindow::onPostLoginFinished(){
//do stuff
}
Mainwindow::retrieveXYZ(){
//code
connect(nam, SIGNAL(finished()), this, SLOT(onGet1RetrieveFinished()));
nam->get();
//code
}
Mainwindow::onGet1RetrieveXYZFinished(){
//do stuff
connect(nam, SIGNAL(finished()), this, SLOT(onGet2RetrieveFinished()));
nam->get();
}
或者我应该使用 QSignalMapper 之类的东西吗? 最 correct/efficient 的方法是什么?我见过有人使用 sender() cast 但我不明白这一点。
基本上我想检索特定的回复 finished() 信号而不是一般的(或 qnam 的)
这个方法可能有用,但对我来说不是很好和干净
这是我们能得到的最好的吗?
将连接方法移动到回复?
我得到了类似的东西:
struct RequestResult {
int httpCode;
QByteArray content;
};
RequestResult
ExecuteRequest(const std::function<QNetworkReply*(QNetworkAccessManager&)>& action,
const std::chrono::milliseconds& timeOut)
{
QEventLoop eLoop;
QTimer timeOutTimer;
QNetworkAccessManager nam;
QObject::connect(&timeOutTimer, &QTimer::timeout, &eLoop, &QEventLoop::quit);
QObject::connect(&nam, &QNetworkAccessManager::finished, &eLoop, &QEventLoop::quit);
timeOutTimer.setSingleShot(true);
timeOutTimer.setInterval(timeOut.count());
timeOutTimer.start();
auto resetTimeOut = [&timeOutTimer]() { timeOutTimer.start(); };
QNetworkReply* reply = action(nam);
QObject::connect(reply, &QNetworkReply::uploadProgress, resetTimeOut);
QObject::connect(reply, &QNetworkReply::downloadProgress, resetTimeOut);
eLoop.exec();
if (!timeOutTimer.isActive())
{
throw std::runtime_error("Time out"); // Probably custom exception
}
const int httpStatus
= reply->attribute(QNetworkRequest::Attribute::HttpStatusCodeAttribute).toInt();
auto content = TakeContent(*reply); // reply->readAll and decompression
return RequestResult{httpStatus, content};
}
然后 get/delete/post/.. 的功能类似于
auto RequestGet(const QNetworkRequest& request) {
return ExecuteRequest([&](QNetworkAccessManager& nam) { return nam.get(request); },
timeOut);
}
auto RequestDelete(const QNetworkRequest& request) {
return ExecuteRequest([&](QNetworkAccessManager& nam) {
return nam.deleteResource(request);
},
timeOut);
}
auto RequestPost(const QNetworkRequest& request, QHttpMultiPart& multiPart)
{
return ExecuteRequest([&](QNetworkAccessManager& nam) {
return nam.post(request, &multiPart);
},
timeOut);
}
然后,对于你的代码,我会做类似的事情
Mainwindow::login()
{
const auto getRes = RequestGet(..);
// ...
const auto postRes = RequestPost(..);
// ...
}
如果你不想阻塞调用,你可以使用 thread 和 future。