HTTP GET リクエストをリモート サーバーに送信しています。さまざまなパラメーターを使用して、関心のあるコンテンツを定義します。特にoutput=xml
、サーバーが XML として応答を返すようにするため、それがクエリに含まれていることを確認します。
クラスHttpRetriever
とそれぞれの間に次の接続がQNetworkReply
ありますQNetworkAccessManager
(slotStartRequest()QNetworkRequest
を参照):
connect(this->reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
SLOT(slotErrorRequest(QNetworkReply::NetworkError)));
connect(this->reply, &QNetworkReply::finished, this, &HttpRetriever::slotFinishRequest);
connect(this->manager, &QNetworkAccessManager::finished, this->reply, &QNetworkReply::deleteLater);
connect(this->reply, &QIODevice::readyRead, this, &HttpRetriever::slotReadyReadRequest);
ここで重要なスロットには、次の宣言があります。
slotFinishRequest():
void HttpRetriever::slotFinishRequest()
{
LOG(INFO) << "Finishing HTTP GET request from URL \"" << this->url.toString() << "\"";
this->reply = Q_NULLPTR;
// Reset validity of reply from a previous request
this->validReply = false;
// Skip validation if it's disabled
if (!this->validateReply)
{
LOG(WARNING) << "Validation disabled. In order to enable it see the \"validate\" and \"validationMode\" in \"settings.ini\"";
this->validReply = true;
}
else
{
// Validate reply
this->validReply = validateReply();
}
if (!this->validReply)
{
return;
}
processReply(); // Parsing
this->processingRequest = false;
}
slotReadyReadRequest():
void HttpRetriever::slotReadyReadRequest()
{
LOG(INFO) << "Received data from \"" << this->url.toString() << "\"";
this->bufferReply = this->reply->readAll();
}
内部では、次のslotFinishRequest()
ように呼び出しますprocessReply()
。
void HttpRetriever::processReply()
{
LOG(INFO) << "Processing reply for request \"" << this->url.toString() << "\"";
LOG(DEBUG) << QString(this->bufferReply);
// Process the XML from the reply and extract necessary data
QXmlStreamReader reader;
reader.addData(this->bufferReply);
// Read the XML reply and extract required data
// TODO
while (!reader.atEnd())
{
LOG(DEBUG) << "Reading XML element";
reader.readNextStartElement();
QXmlStreamAttributes attributes = reader.attributes();
foreach (QXmlStreamAttribute attrib, attributes)
{
LOG(DEBUG) << attrib.name();
}
}
if (reader.hasError())
{
LOG(ERROR) << "Encountered error while parsing XML data:" << reader.errorString();
}
LOG(INFO) << "Sending data to data fusion handler";
// TODO
}
次のスロットを介して HTTP get リクエストをトリガーします。
void HttpRetriever::slotStartRequest(quint32 id)
{
if (this->processingRequest)
{
this->reply->abort();
}
this->processingRequest = false;
// The first request also instantiates the manager. If the slot is called after the instance of HafasHttpRetriever
// is moved to a new thread this will ensure proper parenting
if (!this->manager)
{
this->manager = new QNetworkAccessManager(this);
}
quint32 requestId = generateRequestId(stopId);
if (!this->url.hasQuery())
{
LOG(WARNING) << "Attempting to start request without parameters";
}
// Part of the filters applied to the request to reduce the data received (for more see slotSetRequestParams())
QUrlQuery query(this->url.query());
query.addQueryItem("input", QString::number(requestId));
// TODO Add more filters; see documentation
this->url.setQuery(query);
LOG(INFO) << "Requesting data from \"" << this->url.toString() << "\" with request ID:" << requestId;
QNetworkRequest request(this->url);
this->reply = this->manager->get(request);
// Establish connections from/to the reply and the network access manager
connect(this->reply, SIGNAL(error(QNetworkReply::NetworkError)), this,
SLOT(slotErrorRequest(QNetworkReply::NetworkError)));
connect(this->reply, &QNetworkReply::finished, this, &HttpRetriever::slotFinishRequest);
connect(this->manager, &QNetworkAccessManager::finished, this->reply, &QNetworkReply::deleteLater);
connect(this->reply, &QIODevice::readyRead, this, &HttpRetriever::slotReadyReadRequest);
}
ご覧のとおり、クラスとサーバー間のネットワーク通信の基盤を構築しましたが、XML 応答の解析とそこから必要な情報を抽出する作業はまだ開始していません。
問題は、私が(非常に頻繁に)どちらかを取得していることです
XML データの解析中にエラーが発生しました: 開始タグが必要です。
また
XML データの解析中にエラーが発生しました: ドキュメントの終わりが早すぎます
私のprocessReply()
機能で。これは、大量の返信 (数百行から数千行) を受け取るたびに発生します。私が小さなものを手に入れたときは決して起こりません(30-40行がギブまたはテイク)。
したがって、問題は明らかに、受信しているデータの量のどこかにあり、それが (または、受信したデータのチャンクをバッファリングするすべての Qt コンポーネント) によってまとめられる方法、QNetworkAccessManager
および/またはインスタンスをセットアップした方法にある可能性があります。私のクラスのネットワーク関連のコンポーネント。また、ここで重要なことに注意する必要があります。つまり、私のブラウザー ( HttpRequesterアドオンを備えた最新の Firefox) では、XML のサイズに関係なく、常に完全な XML を受信していることです。したがって、これは私のアプリケーション固有の問題であり、システムのネットワーク設定とは関係ありません。