Qt QNetworkReply readAll возвращает пустое значение при повторном запросе того же URL-адреса

Это чисто для целей тестирования и для моего любопытства. Я использую свой класс DataDownloader для получения списка данных с сервера. Он работает с разными URL-адресами, такими как http://tiny-file-url, http://big-file-url. Но если я передам два одинаковых URL-адреса, http://tiny-file-url, http://tiny-file-url и данные из http://tiny-file-url довольно мал, второй ответ от QNetworkAccessManager пуст. Однако два http://big-file-url работают. Мне интересно, делает ли QNetworkAccessManager какое-то волшебство при запросе небольших данных с одного и того же URL-адреса? Кажется, я не могу получить какую-либо соответствующую информацию на сайте документации Qt.

Вот мой класс DataDownloader:

class DataDownloader : public QObject
{
    Q_OBJECT

public:
    explicit DataDownloader(QObject* parent = 0);
    virtual ~DataDownloader();

    QByteArray data() const;
    void cancel();
    void download(QUrl url);

    signals:
    void isComplete();

    private slots:
    void complete(QNetworkReply* reply);

    private:
    QNetworkAccessManager m_NetworkManager;
    QByteArray m_Data;
    QNetworkReply* m_pReply;
};

DataDownloader::DataDownloader(QUrl url, QObject* parent) :QObject(parent)
{
    connect(&m_NetworkManager, SIGNAL(finished(QNetworkReply*)),
            SLOT(complete(QNetworkReply*)));
}

DataDownloader::~DataDownloader()
{
}

void DataDownloader::complete(QNetworkReply* reply)
{
    // in the first download it returns data
    // but the second time m_Data is empty
    m_Data = reply->readAll();
    reply->deleteLater();

    if (!m_Data.isEmpty()) {
        // no signal on the second try
        emit isComplete();
    }
}

QByteArray DataDownloader::data() const
{
    return m_Data;
}

void DataDownloader::cancel()
{
    m_pReply->abort();
}

void DataDownloader::download(QUrl url)
{
    QNetworkRequest request(url);
    m_pReply = m_NetworkManager.get(request);
}

Код, который вызывает этот DataDownloader, выглядит следующим образом:

void PluginManager::downloadPlugins()
{
    m_DownloadIndex++;

    savePlugin();

    if (m_DownloadIndex < m_PluginList.size()) {
        QUrl url;
        // alway return the same url here
        QString pluginUrl = getPluginUrl(m_PluginList.at(m_DownloadIndex));
        url.setUrl(pluginUrl);

        if (m_pPluginDownloader == NULL) {
            m_pPluginDownloader = new DataDownloader();
            // call this function again when isComplete is signaled
            connect(m_pPluginDownloader, SIGNAL(isComplete()), this, SLOT(downloadPlugins()));
        }
        m_pPluginDownloader->download(url);
    }
}

person Jerry    schedule 06.02.2015    source источник
comment
Предложение дня по случайному коду: гораздо лучше создать только один QNetworkAccessManager вместо одного для каждого загрузчика.   -  person peppe    schedule 06.02.2015
comment
Кстати, вы на 100 % уверены, что tiny-file-url всегда работает должным образом?   -  person alediaferia    schedule 09.02.2015
comment
Я вполне уверен в этом, так как могу загрузить данные в виде файла (содержащего отладочный текст) и открыть его в редакторе.   -  person Jerry    schedule 09.02.2015
comment
Извините, если вы имеете в виду, работает ли фактический URL-адрес крошечного файла, это просто для иллюстрации, это недействительный URL-адрес.   -  person Jerry    schedule 09.02.2015
comment
Нет, вы меня поняли, я имел в виду ваш фактический URL :)   -  person alediaferia    schedule 09.02.2015


Ответы (1)


Я думаю, что здесь isComplete излучается до того, как вы подключите его к downloadPluginsslot. Попробуйте сначала подключить этот сигнал, а затем выполните действие загрузки:

m_pPluginDownloader = new DataDownloader(url);

connect(m_pPluginDownloader, SIGNAL(isComplete()), this, SLOT(downloadPlugins()));

m_pPluginDownloader.download();

Вместо того, чтобы выполнять действие get в конструкторе, сделайте это в слоте с именем download :

void DataDownloader::download()
{
    QNetworkRequest request(url);
    m_pReply = m_NetworkManager.get(request);
}

Другой момент заключается в том, что нет необходимости создавать новый экземпляр DataDownloaderкаждый раз. Вы можете создать экземпляр в конструкторе PluginManager и один раз подключить сигнал isComplete. Затем вы можете указать URL-адрес в качестве аргумента в слоте download.

person Nejat    schedule 06.02.2015
comment
Привет, Неджат, спасибо за ответ. Я попробовал ваше предложение, оно работает так же, как и раньше. Я все еще получаю пустые данные при второй загрузке. - person Jerry; 09.02.2015
comment
Привет, Неджат, кажется, эта проблема возникает только с двумя идентичными URL-адресами, и данные с этих URL-адресов малы. Я собираюсь протестировать два разных URL-адреса, которые содержат небольшие данные, чтобы увидеть, имеет ли это какое-то значение. - person Jerry; 09.02.2015
comment
Итак, вот результаты моих тестов: URL-адрес крошечного файла, URL-адрес большого файла работает с URL-адресом большого файла, URL-адрес большого файла работает с URL-адресом крошечного файла-1, URL-адрес крошечного файла-2 работает с крошечным файлом. -url, крошечный-файл-url возвращает пустой при втором запросе - person Jerry; 09.02.2015