Russian Qt Forum
Ноябрь 24, 2024, 01:02 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: При перехвате QNetworkReply отсутствует контент  (Прочитано 13721 раз)
serge-markin
Гость
« : Август 20, 2010, 10:52 »

Создаю свой NetworkAccessManager, подключаю к его сигналу finished свой слот с обработчиком. Подцепляю этот менеджер к WebView.
Код:
   networkAccessManager = new QNetworkAccessManager();
   connect(networkAccessManager, SIGNAL(finished(QNetworkReply*)),
           this, SLOT(processNetworkReply(QNetworkReply*)));
   ui->rawReponseView->page()->setNetworkAccessManager(networkAccessManager);

Определяю слот с обработчиком.
Код:
void MainWindow::processNetworkReply(QNetworkReply* networkReply)
{
   if (!networkReply->error())
   {
     
      QByteArray content = networkReply->readAll();
      qDebug() << "content.length(): " << content.length();
      qDebug() << "content: " << content;

      QList<QByteArray> listHeaders;
      listHeaders = networkReply->rawHeaderList();
      QByteArray header;
      qDebug() << "*******************************";
      foreach(header, listHeaders) {
         qDebug("%s: %s", header.data(), networkReply->rawHeader(header).data());
      }
      qDebug() << "*******************************";
      qDebug() << "Status code: " << networkReply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString();
      qDebug() << "*******************************";
      qDebug() << "networkReply->isFinished(): " << networkReply->isFinished();
      qDebug() << "networkReply->bytesAvailable(): " << networkReply->bytesAvailable();
      qDebug() << "networkReply->isReadable(): " << networkReply->isReadable();
      qDebug() << "ContentLengthHeader: " << networkReply->header(QNetworkRequest::ContentLengthHeader).toString();
      qDebug() << "------------------------";
      }
}

После этого делаю запросы к разным страницам, а также, непосредственно, напрямую к изображениям.

Слот срабатывает как нужно - при каждом обращении к ресурсам. Заголовки правдоподобные - url правильные, ContentLenght тоже правдоподобный. Проблема в том, что в переменную content ничего не загружается. Т.е. я не могу получить контент, который получает браузер.

Вообще, я хочу перехватывать этот контент и сохранять его на диск.

Перелопатил интернет - ничего не нашел по данной проблеме. Есть какие нибудь идеи?
Заранее спасибо.

Записан
SABROG
Гость
« Ответ #1 : Август 20, 2010, 11:19 »

Код
C++ (Qt)
qDebug() << "content: " << content;

Ну если content.size() правильный, то данные есть. Попробуй выведи в виде HEX'a, чтобы понять есть ли там вообще что-то:

Код
C++ (Qt)
qDebug() << "content: " << content.toHex();
 
Записан
serge-markin
Гость
« Ответ #2 : Август 20, 2010, 12:10 »

content.size() = 0

Т.е. проблема не в отображении, а где-то глубже
Записан
BRE
Гость
« Ответ #3 : Август 20, 2010, 12:12 »

content.size() = 0

Т.е. проблема не в отображении, а где-то глубже
Думаю весь контент уже забрала QWebPage для того, что бы отобразить.
Записан
serge-markin
Гость
« Ответ #4 : Август 20, 2010, 12:14 »

В таком случае где его можно перехватить?
Записан
BRE
Гость
« Ответ #5 : Август 20, 2010, 12:21 »

В таком случае где его можно перехватить?
Вопрос интересный.  Улыбающийся
Если ты подключишься к readyRead и будешь считывать контент, то его не получит объект QWebPage и расстроиться.
Извратиться и после чтения контента возвращать его обратно в буфер приема...? (приличного решения сразу как-то и не предложу).
Дублировать запрос....?
Записан
BRE
Гость
« Ответ #6 : Август 20, 2010, 12:23 »

Стоп, у QIODevice есть же семейство методов peek.
Для себя получишь контент с помошью peek, а QWebPage уже вычитает его.
Записан
serge-markin
Гость
« Ответ #7 : Август 20, 2010, 13:33 »

Сделал субкласс от QNetworkAccessManager, переопределил createRequest, повесил обработчик на readyRead и выхватываю данные методом peek. Вроде работает.

Код:
QNetworkReply* AdvancedNetworkAccessManager::createRequest(
      Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
{
   QNetworkReply* networkReply = QNetworkAccessManager::createRequest(op, request, outgoingData);
   connect(networkReply, SIGNAL(readyRead()), this, SLOT(processReply()));
   return networkReply;
}

void AdvancedNetworkAccessManager::processReply()
{
   QNetworkReply* currentReply = qobject_cast<QNetworkReply*>(sender());
   int bytesAvailable = currentReply->bytesAvailable();
   QByteArray content = currentReply->peek(bytesAvailable);
   qDebug() << "content size: " << content.size();
   qDebug() << "content: " << content.toHex();
}

Подскажите пожалуйста вот что: в этом слоте я получу весь ответ сервера или только фрагмент. Например если будет закачиваться большой файл.
Записан
BRE
Гость
« Ответ #8 : Август 20, 2010, 13:36 »

Подскажите пожалуйста вот что: в этом слоте я получу весь ответ сервера или только фрагмент. Например если будет закачиваться большой файл.
Фрагментами.
Записан
serge-markin
Гость
« Ответ #9 : Август 20, 2010, 13:39 »

Как лучше всего организовать прием фрагментами и сборку? Может есть ссылка на толковый сниппет? Не хочу изобретать велосипед с глюками.
Записан
BRE
Гость
« Ответ #10 : Август 20, 2010, 13:42 »

Как лучше всего организовать прием фрагментами и сборку? Может есть ссылка на толковый сниппет? Не хочу изобретать велосипед с глюками.
Код
C++ (Qt)
 
class AdvancedNetworkAccessManager : ...
{
...
  QByteArray content;
};
 
void AdvancedNetworkAccessManager::processReply()
{
  QNetworkReply* currentReply = qobject_cast<QNetworkReply*>(sender());
  if( !currentReply )
     return;
 
  int bytesAvailable = currentReply->bytesAvailable();
  content += currentReply->peek(bytesAvailable);
}
 
Записан
BRE
Гость
« Ответ #11 : Август 20, 2010, 13:48 »

Но есть здесь один тонкий момент.
QWebPage возможно выберет из ответа не все данные, тогда произойдет их дублирование в нашем буфере, или мы получим все доступные данные, а когда QWebPage начнет их читать, данных прибавиться и тогда у нас в буфере этих данных не будет.
Записан
serge-markin
Гость
« Ответ #12 : Август 20, 2010, 13:49 »

Так он будет сваливать все в одну кучу. Ведь через этот NetworkAccessManager идет множество асинхронных запросов-ответов. Тут напрашивается схема при которой я должен накапливать фрагменты данных по каждому их висящих на закачке ответов. Что-то вроде ассоциативной таблицы в которой висят все текущие ответы. Но мне кажется это я усложняю и есть более изящное решение. Возможно есть сигнал по которому можно поймать NetworkReply со всеми данными, но который еще никто не трогал? Если ловить finished у NetworkReply - данных уже нет - "Все сожрал хомяк".
Записан
BRE
Гость
« Ответ #13 : Август 20, 2010, 14:06 »

Так он будет сваливать все в одну кучу. Ведь через этот NetworkAccessManager идет множество асинхронных запросов-ответов.
Точно-точно.
Как вариант
Код
C++ (Qt)
class ReplySaver : public QObject
{
ReplySaver( const QUrl &url, ... ) : m_url( url ), m_finish( false ) {}
...
public:
bool isFinished() const { return m_finish; }
QByteArray content() const { return m_content; }
 
public slots:
void processReply() { ... }
void finished() { m_finish = true; }
 
private:
QByteArray m_content;
QUrl m_url;
bool m_finish;
};
 
QNetworkReply* AdvancedNetworkAccessManager::createRequest(
     Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
{
  QNetworkReply* networkReply = QNetworkAccessManager::createRequest(op, request, outgoingData);
  ReplySaver *saver = new ReplySaver( networkReply->url() );
  connect(networkReply, SIGNAL(readyRead()), saver, SLOT(processReply()));
  connect(networkReply, SIGNAL(finished()), saver, SIGNAL(finished()));
 
  // Сохраняем в списке
  // В класс добавляем методы для доступа к элементам списка saverList
  saverList.append( saver );
 
  return networkReply;
}
Записан
Tonal
Гость
« Ответ #14 : Декабрь 06, 2010, 11:59 »

Есть одна тонкость:
Если мне склероз не изменяет, то порядок получения сигналов в Qt не специфицирован.
А если так, то мы вполне можем получить сигнал readyRead уже после того, как данные из объекта networkReply уже были прочитаны.
В таком случае bytesAvailable возвернёт 0 и peek-у будет нечего читать...

Т. е. получается нам пока просто везёт что этот код работает...
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.343 секунд. Запросов: 21.