Russian Qt Forum

Qt => Работа с сетью => Тема начата: serge-markin от Август 20, 2010, 10:52



Название: При перехвате QNetworkReply отсутствует контент
Отправлено: 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 ничего не загружается. Т.е. я не могу получить контент, который получает браузер.

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

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



Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: SABROG от Август 20, 2010, 11:19
Код
C++ (Qt)
qDebug() << "content: " << content;

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

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


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: serge-markin от Август 20, 2010, 12:10
content.size() = 0

Т.е. проблема не в отображении, а где-то глубже


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 20, 2010, 12:12
content.size() = 0

Т.е. проблема не в отображении, а где-то глубже
Думаю весь контент уже забрала QWebPage для того, что бы отобразить.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: serge-markin от Август 20, 2010, 12:14
В таком случае где его можно перехватить?


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 20, 2010, 12:21
В таком случае где его можно перехватить?
Вопрос интересный.  :)
Если ты подключишься к readyRead и будешь считывать контент, то его не получит объект QWebPage и расстроиться.
Извратиться и после чтения контента возвращать его обратно в буфер приема...? (приличного решения сразу как-то и не предложу).
Дублировать запрос....?


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 20, 2010, 12:23
Стоп, у QIODevice есть же семейство методов peek.
Для себя получишь контент с помошью peek, а QWebPage уже вычитает его.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: serge-markin от Август 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();
}

Подскажите пожалуйста вот что: в этом слоте я получу весь ответ сервера или только фрагмент. Например если будет закачиваться большой файл.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 20, 2010, 13:36
Подскажите пожалуйста вот что: в этом слоте я получу весь ответ сервера или только фрагмент. Например если будет закачиваться большой файл.
Фрагментами.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: serge-markin от Август 20, 2010, 13:39
Как лучше всего организовать прием фрагментами и сборку? Может есть ссылка на толковый сниппет? Не хочу изобретать велосипед с глюками.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 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);
}
 


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 20, 2010, 13:48
Но есть здесь один тонкий момент.
QWebPage возможно выберет из ответа не все данные, тогда произойдет их дублирование в нашем буфере, или мы получим все доступные данные, а когда QWebPage начнет их читать, данных прибавиться и тогда у нас в буфере этих данных не будет.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: serge-markin от Август 20, 2010, 13:49
Так он будет сваливать все в одну кучу. Ведь через этот NetworkAccessManager идет множество асинхронных запросов-ответов. Тут напрашивается схема при которой я должен накапливать фрагменты данных по каждому их висящих на закачке ответов. Что-то вроде ассоциативной таблицы в которой висят все текущие ответы. Но мне кажется это я усложняю и есть более изящное решение. Возможно есть сигнал по которому можно поймать NetworkReply со всеми данными, но который еще никто не трогал? Если ловить finished у NetworkReply - данных уже нет - "Все сожрал хомяк".


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Август 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;
}


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: Tonal от Декабрь 06, 2010, 11:59
Есть одна тонкость:
Если мне склероз не изменяет, то порядок получения сигналов в Qt не специфицирован.
А если так, то мы вполне можем получить сигнал readyRead уже после того, как данные из объекта networkReply уже были прочитаны.
В таком случае bytesAvailable возвернёт 0 и peek-у будет нечего читать...

Т. е. получается нам пока просто везёт что этот код работает...


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Декабрь 06, 2010, 12:05
Т. е. получается нам пока просто везёт что этот код работает...
К сожалению да, никаких механизмов для установки порядка вызовов слотов нет и не предвидиться.
Остается только надеяться, что все останется по прежнему и слоты будут вызываться в порядке их подключения.


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: ufna от Декабрь 06, 2010, 17:00
А почему надо перехватывать именно QNAM? Почему нельзя брать данные из страниц?


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: BRE от Декабрь 06, 2010, 17:07
А почему надо перехватывать именно QNAM? Почему нельзя брать данные из страниц?
http://www.forum.crossplatform.ru/index.php?showtopic=6052


Название: Re: При перехвате QNetworkReply отсутствует контент
Отправлено: ufna от Декабрь 06, 2010, 17:24
Брр, приду домой, посмотрю как я реализовывал сию схему, т.к. проблем там таких не было.