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

How do I make my own custom QNetworkReply?

我一直在尝试创建自己的自定义 QNetworkReply class,其中 return 个来自回复的自定义字节。我从我的 QNetworkAccessManager::createRequest() 重载中执行 return class 我也执行了重载。我的问题是,我的函数重载 none 被调用,因此 QWebView 的请求失败,因为回复是 "corrupted"。我试图从 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;
}

class的用法是这样的:

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;
   }

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

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

确实有效。