2016-11-25 6 views
0

私は、OpenEmbeddedプロジェクトのQt5組み込み層を使用して、組み込みのRESTful APIクライアントを作成しています。私は、クライアントが、何が起こっているのかを私のサーバーに知らせるための単純な非同期要求を送ることができるようにしたい。そして、クライアントがサーバーからデータを同期させる必要がある。QNetworkReplyを削除する最も良い方法は何ですか?

私は2つの機能を書いています.1つはリクエストを送信し、もう1つはレスポンスを取得する機能です。だから私がその反応を気にしなければ、私は最初のものだけを使う。

2番目のレスポンスでレスポンスを使用できるように、私は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

QNetworkReplyは、エラーが発生しても常にfinished()を発します。

deleteLater()その信号に接続されたスロットでも呼び出すことができるので、その部分は問題ありません。

しかし、私はあなたのgetResponse()の中のオンのようなネストされたイベントループは、「面白い」行動につながる可能性があるので、リクエストを処理するより非同期的な方法を検討することをお勧めします。スレッドプログラム。

+0

この問題を回避するために複数のQNetworkReplyを管理する方法はありますか? – didil

+0

要求メソッドのすべて1つが新しいネットワーク応答オブジェクトを返し、マネージャの信号のいくつかはそれぞれの応答へのポインタを引数として持つことすらできます。 'QNetworkAccessManager :: finished()' また、返信信号に接続されたスロットで 'QObject :: sender()'を使って、何かを通知した多くの返信のどれを見つけることができます。 もう1つの方法は、返信ごとに個別の返信ハンドラオブジェクトを持たせることです。返信ごとに1つのシグナル受信者インスタンスがあります。 –

+0

OK 'QNetworkAccessManager :: finished(QNetworkReply *)'を使用します。 – didil

関連する問題