删除QNetworkReply的最佳方法是什么?

时间:2016-11-25 11:03:53

标签: c++ qt rest qt5

我正在使用OpenEmbedded项目的Qt5 Embedded层编写嵌入式RESTful API客户端。我希望我的客户端能够发送一个简单的异步请求来通知我的服务器发生了什么,另一种情况是我的客户端需要同步来自服务器的数据。

为此,我编写了两个函数,一个用于发送请求,另一个用于获取响应。因此,如果我不关心响应,我只使用第一个。

为了能够使用第二个响应,我使用QNetworkReply *作为我班级的成员。为了使QNetworkReply保持活跃,我还将QNetworkAccessManager设置为我的班级成员。

#include <QtNetwork>

class ApiClient : public QObject
{
    Q_OBJECT

public:

    ApiClient(QObject *parent = 0);

private:

    QString host;
    QString key;
    quint32 replyTimeout;
    QNetworkAccessManager manager;
    QNetworkReply *reply;

    void sendRequest(const QString &method, const QVariantMap &params = QVariantMap());
    QVariantMap getResponse() const;
};

apiclient.cpp文件:

#include "apiclient.h"

ApiClient::ApiClient(QObject *parent) : QObject(parent)
{

}

void ApiClient::sendRequest(const QString &method, const QVariantMap &params)
{
    QUrl url(QString("%1/%2/").arg(host).arg(method));

    QUrlQuery query;
    query.addQueryItem("key", key);

    if (!params.empty())
    {
        QMapIterator<QString, QVariant> it(params);
        while (it.hasNext())
        {
            it.next();
            query.addQueryItem(it.key(), it.value().toString());
        }
    }

    url.setQuery(query);
    qDebug() << "url: " << url.toString();

    reply = manager.get(QNetworkRequest(url));
}

QVariantMap ApiClient::getResponse() const
{
    if (!reply)
    {
        qFatal("No request sent!");
    }

    QTimer timer;
    timer.setSingleShot(true);

    QEventLoop loop;
    connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
    connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    timer.start(replyTimeout);
    loop.exec();

    if (timer.isActive())
    {
        timer.stop();

        if (reply->error())
        {
            qFatal("Wrong reply!");
        }

        int code = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
        if (code != 200)
        {
            qFatal("Invalid server response!");
        }

        QJsonDocument result = QJsonDocument::fromJson(reply->readAll());

        if (result.isNull())
        {
            qFatal("Invalid JSON!");
        }

        reply->deleteLater();
        return result.object().toVariantMap();
    }

    disconnect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    reply->abort();
    reply->deleteLater();
    return QVariantMap();
}

这是一个很好的方法吗?当发出其他信号时,我应该如何管理QNetworkReply指针(即error(),sslErrors(),...)?

1 个答案:

答案 0 :(得分:1)

QNetworkReply将始终发出finished(),即使发生错误也是如此。

deleteLater()甚至可以在连接到该信号的插槽中调用,因此该部分应该没问题。

但是我建议我们研究一种处理请求的更加异步的方法,像getResponse()中的on这样的嵌套事件循环可以导致&#34;有趣的&#34;行为,因为你基本上可以在单线程程序中进入重入的情况。