Qt не может выполнить HTTP-запрос в классе - PullRequest
0 голосов
/ 02 ноября 2018

Я пытаюсь создать класс, который обрабатывает запросы HTTP get; У меня есть служба REST, и мне нужно выполнить некоторые операции чтения данных JSON. Другими словами, этот класс просто получает HTTP и анализирует JSON.

.h

#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H

#include <QUrl>
#include <QObject>
#include <functional>
#include <QNetworkReply>
#include <QNetworkAccessManager>
#include <QDebug>

class HTTPRequest : public QObject {

    Q_OBJECT

private:
    QUrl url;
    QNetworkAccessManager* mAccessManager;
    std::function<void(const QString&)> action;

private slots:
    void replyFinished(QNetworkReply* reply);

public:
    explicit HTTPRequest(QObject *parent = nullptr, const QUrl& _url = {});
    void executeGet(const std::function<void(const QString&)>& onComplete);

};

#endif // HTTPREQUEST_H

.cpp

#include "httprequest.h"

HTTPRequest::HTTPRequest(QObject *parent, const QUrl& _url) : QObject(parent), url(_url) {
    mAccessManager = new QNetworkAccessManager(this);
    connect(mAccessManager, &QNetworkAccessManager::finished, this, &HTTPRequest::replyFinished);
}

void HTTPRequest::executeGet(const std::function<void(const QString&)>& onComplete) {
    QNetworkRequest request{QUrl{url}};
    mAccessManager->get(request);
    //qDebug() << "executeGet";

    action = onComplete;
    //qDebug() << "assign";
}

void HTTPRequest::replyFinished(QNetworkReply* reply) {
    //qDebug() << "onFinish";
    if (reply->error() == QNetworkReply::NoError) {
        action(QString{reply->readAll()});
    } else {
        throw std::runtime_error(reply->errorString().toStdString());
    }
    reply->deleteLater();
}

Этот класс имеет только метод executeGet. Он принимает лямбду, потому что я хочу выполнить его в разных местах и ​​хочу, чтобы он использовался следующим образом:

void MainWindow::on_pushButton_clicked() {
    HTTPRequest req{this, QUrl{"http://www.website.com/1.json"}};
    req.executeGet([&](const QString& response){
        //work with response
    });
}

void MainWindow::on_pushButton_2_clicked() {
    HTTPRequest req{this, QUrl{"http://www.website.com/2.json"}};
    req.executeGet([&](const QString& response){
        //work with response
    });
}

Если вы попытаетесь раскомментировать qDebug(), вы увидите сообщения executeGet и , назначенные , но тогда вы не увидите onFinish . Почему?

Возможно, я что-то не так делаю с лямбдой?

1 Ответ

0 голосов
/ 02 ноября 2018

Ваши функции, в которых вы создаете HTTPRequest объекты и выполняете их, выделяют req в стеке как локальную переменную. Следовательно, как только эти функции завершают работу, HTTPRequest удаляется, даже если фактический запрос все еще выполняется в фоновом режиме. Вам необходимо создать HTTPRequest объекты в куче и убедиться, что они остаются до тех пор, пока фактический запрос не будет завершен, и ваша полная лямбда не будет названа:

void MainWindow::on_pushButton_clicked() {
    auto *req = new HTTPRequest(this, QUrl(...));
    req->executeGet([req](const QString &response) {
        // Do other stuff...

        // Make sure we only delete `req` after the request finishes.
        delete req;
    });
}
...