How can I read content (http response body) from a QNetworkReply
Asked Answered
L

1

7

I'm using qt5.3 and I googled a lot before I post.

I want to read data from QNetworkReply. I have a QWebView and I also need the http response to be read by QWebView to display the webpage. What I need is just to log the web content or whatever response to http posts.

The problem is QNetworkReply is something that can only be read once.

  1. If I call readAll() when I pick readyRead() signal, I will get the full data. But it will be cleared so QWebView displays nothing (it won't get any reply data).

  2. Or if I pick finished() signal, since the data is already read by QWebView (or QNetworkAccessManager), I get nothing if I call readAll() here. Is there somewhere that QNetworkReply, or manager or any class, stores the data which I can still read?

In #1 I can get part of the data if I call peek(). This function does not clear the response data. But it won't work if the response body is big. The QNetworkReply is a sequential thing that I can neither know its data nor read further than buffered.

I have no idea of how to do with this.....

I just want to monitor and log the request and response body of any request made on my QWebView ...

Edit: note that my data to read from response is as large as 1MB so it won't be ok to peek the whole data without further reading.

Lifelong answered 5/8, 2014 at 15:26 Comment(1)
Both your points 1 and 2 stem from your misunderstanding of how QNetworkReply should be used. In programming, there is no such thing as things that can only be read once. Either you buffer it or you don't; in which you end up losing the data.Stempson
I
2

You can create your own subclass of QNetworkAccessManager and override virtual function createRequest. Call base class implementation to get the response object and connect readyRead signal to some slot that will capture the data. In that slot call peek function to read data so that WebKit will get the data also :

class NetworkAccessManagerProxy : public QNetworkAccessManager {
Q_OBJECT

signals:

    void dataGot(QByteArray data);

public:
    NetworkAccessManagerProxy(QObject * parent = 0)
         : QNetworkAccessManager()
    {
    }

    virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice *outgoingData)
    {
        reply = QNetworkAccessManager::createRequest(op, request, outgoingData);
        connect(this,SIGNAL(readyRead()), SLOT(readInternal()));
        return reply;
    }

private slots:

     void readInternal()
     {
        QByteArray data = reply->peek(reply->bytesAvailable());
        emit dataGot(data);
     }

private:

    QNetworkReply* reply;
};

After creating QWebPage object, call setNetworkAccessManager and pass a newly created instance of your subclass :

QWebPage * page = new QWebPage; 
page->setNetworkAccessManager(new NetworkAccessManagerProxy());
page->mainFrame()->load(url);

webView->setPage(page);
Indiaindiaman answered 5/8, 2014 at 16:22 Comment(2)
This works when reply data is small. My data to read is as large as 1MB and bytesAvailable() mostly returns some value around 10000 bytes.Lifelong
I think the connect statement should be connect(reply,SIGNAL(readyRead()),this,SLOT(readInternal())).Lodicule

© 2022 - 2024 — McMap. All rights reserved.