如何制作自己的自定义 QNetworkReply?

Posted

技术标签:

【中文标题】如何制作自己的自定义 QNetworkReply?【英文标题】:How do I make my own custom QNetworkReply? 【发布时间】:2018-02-01 18:54:43 【问题描述】:

我一直在尝试创建自己的自定义 QNetworkReply 类,该类从回复中返回自定义字节。我确实从我也重载的 QNetworkAccessManager::createRequest() 重载中返回了该类。我的问题是,我的函数重载都没有被调用,因此 QWebView 的请求失败,因为回复是“损坏的”。我试图从 Qt 测试库的 FakeReply 中获得一些灵感,但我的工作失败了。

这是我的代码:

class FakeReply : public QNetworkReply

    Q_OBJECT

public:
    FakeReply(const QNetworkRequest& request, QByteArray &data, QObject* parent = 0);
    ~FakeReply();
    QByteArray readAll();
    QByteArray read(qint64 maxSize);
    qint64 peek(char *buffer, qint64 maxlen);
    QByteArray peek(qint64 maxLen);
    qint64 size() const;
    virtual qint64 bytesAvailable() const;
    bool isFinished() const;
    virtual void abort();
    virtual void close();
    bool isSequential() const;
protected:
    qint64 readData(char*, qint64) override;
private:
    QByteArray data;
;

还有 .cpp 文件:

FakeReply::FakeReply(const QNetworkRequest &request, QByteArray &bytes, QObject *parent)
    : QNetworkReply(parent),
      data(bytes)

    setOperation(QNetworkAccessManager::GetOperation);
    setRequest(request);
    setUrl(request.url());
    open(QIODevice::ReadOnly);
    setFinished(true);
    emit finished();


FakeReply::~FakeReply()

    close();


QByteArray FakeReply::readAll()

    qDebug() << "FakeReply::readAll() got called!";
    size_t len = data.length();
    const char *bytes = static_cast<const char*>(data.data());
    char *buffer = static_cast<char*>(malloc(len));
    ASSERT(buffer != NULL, "run out of memory");
    memcpy(buffer, bytes, len);
    QByteArray output;
    output.setRawData(buffer, len);
    data = data.remove(0, len);
    return output;


QByteArray FakeReply::read(qint64 maxSize)

    qDebug() << "QByteArray FakeReply::read() got called!";
    static char* buffer = nullptr;
    if(bytesAvailable() == 0) 
        return QByteArray();
    
    size_t len = computeMaxNumberOfBytes(maxSize);
    if(buffer != nullptr) 
        free(buffer);
    
    buffer = static_cast<char*>(malloc(len));
    ASSERT(buffer != NULL, "run out of memory");
    memcpy(buffer, data.data(), len);
    data = data.remove(0, len);
    QByteArray output;
    output.setRawData(buffer, len);
    return output;


qint64 FakeReply::peek(char *buffer, qint64 maxlen)

    qDebug() << "FakeReply::peek() got called!";
    size_t len = computeMaxNumberOfBytes(maxlen);
    memcpy(buffer, data.data(), len);
    return static_cast<qint64>(len);


QByteArray FakeReply::peek(qint64 maxlen)

    qDebug() << "FakeReply::peek(qint64 maxlen) got called!";
    QByteArray output;
    output.setRawData(data.data(), computeMaxNumberOfBytes(maxlen));
    return output;


qint64 FakeReply::size() const

    return data.length();


qint64 FakeReply::bytesAvailable() const

    qDebug() << "FakeReply::bytesAvailable()";
    return data.length();


bool FakeReply::isFinished() const

    qDebug() << "FakeReply::isFinished() got called!";
    return true;


void FakeReply::abort()

    qDebug() << "FakeReply::abort() got called!";


void FakeReply::close()

    qDebug() << "FakeReply::close() got called!";


bool FakeReply::isSequential() const

    qDebug() << "FakeReply::isSequential() const got called!";
    return false;


qint64 FakeReply::readData(char *, qint64)

    qDebug() << "FakeReply::readData() got called!";
    return 0;

类是这样使用的:

QNetworkReply *MyNetworkAccessManager::createRequest(QNetworkAccessManager::Operation op, const QNetworkRequest &request, QIODevice *outgoingData)

     QString path = request.url().path();
    QNetworkReply *reply = QNetworkAccessManager::createRequest(op, request, outgoingData);

     if(path == QStringLiteral("/testing")) 
         QByteArray response = waitThenReadAll(reply);
         return new FakeReply(request, response);
     
     return reply;
   

【问题讨论】:

所以你的 MyNetworkAccessManager::createRequest() 方法没有被调用?您可以为您的访问管理器发布 *.h 文件吗? 我的MyNetworkAccessManager::createRequest() 确实被调用了,但我的FakeReply 中的所有方法都不是由MyNetworkAccessManager::createRequest() 返回的。 【参考方案1】:

对于任何有同样问题的人,我从here 得到了一些代码示例的答案:我的代码中缺少的是我使用的是emit finish() 而不是

QTimer::singleShot(0, this, SIGNAL(readyRead()));
QTimer::singleShot(0, this, SIGNAL(finished()));

确实有效。

【讨论】:

好的,我确实看到了问题。你让它工作。那挺好的。您的问题是您在构造函数中调用了emit finished()。信号在那里不起作用,因为该对象实际上还不存在(即:对new FakeReply(...) 的调用尚未返回),因此没有任何连接。但这是一个很好的解决方法。

以上是关于如何制作自己的自定义 QNetworkReply?的主要内容,如果未能解决你的问题,请参考以下文章

如何设计制作JavaWeb项目的自定义桌面实现,求源码?新手谢谢!

无论如何要为Android中的来电和去电制作我的自定义用户界面吗?

如何制作使用自定义 TestFixture 和 Test 属性的 SpecFlow 插件?

如何制作自定义音频格式和自定义播放器

如何制作可拉伸的自定义 UITablecell

如何制作突出显示的自定义按钮[重复]