1. 程式人生 > >QT實現HTTP請求(超時阻塞)

QT實現HTTP請求(超時阻塞)

postdata.hpp

#ifndef POSTDATA_HPP
#define POSTDATA_HPP

class PostData : public QObject
{
    Q_OBJECT

public:

    explicit PostData(QObject *parent = nullptr);
    ~PostData();

    /* 提交圖片到PHP */
    void postImage(QString classfied, QString suffix, QByteArray image, int timeout = 3000);
    /* 提交Log到PHP */
    void postLog(QString log, int timeout = 3000);

signals:

public slots:

    void finished();

private:

    std::shared_ptr<QNetworkAccessManager> m_pManager;
    // 請求地址
    QString m_saveImgUrl = "http://localhost/SaveImg.php";
    QString m_saveLogUrl = "http://localhost/SaveLog.php";
};

postdata.cpp

#include <QUrl>
#include <QByteArray>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QHttpMultiPart>
#include <QElapsedTimer>
#include <QCoreApplication>
#include <QJsonObject>
#include <QJsonDocument>
#include <QTimer>

#include "PostData.h"

using namespace std;

PostData::PostData(QObject *parent) : QObject(parent){
    /* 例項化QNetworkAccessManager */
    m_pManager.reset(new QNetworkAccessManager);
}

PostData::~PostData(){
}

void PostData::finished(){
    QNetworkReply* reply = (QNetworkReply*) sender();
    if (!reply->isFinished()) {
        qWarning() << "post data time out";
    }
    /* 請求收到的結果 */
    QByteArray responseByte = reply->readAll();
    if (!responseByte.isEmpty()) {
        /* 錯誤處理 */
        if (reply->error() == QNetworkReply::NoError) {
            qWarning() << "post data success";
        } else {
            qWarning() <<"post data handle errors here";
            QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
            /* statusCodeV是HTTP伺服器的相應碼,reply->error()是Qt定義的錯誤碼 */
            qWarning() << "status code: " << statusCodeV.toInt();
            qWarning() << "status code: " << (int)reply->error();
        }
        qWarning() << "response: " << responseByte;
    }
    disconnect(reply, &QNetworkReply::finished, this, &PostData::finished);
    reply->deleteLater();
}

void PostData::postImage(QString classfied, QString suffix, QByteArray image, int timeout){

    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);

    /* 部件圖片類別 */
    QHttpPart dataPart;
    dataPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
    dataPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"data\""));
    QJsonObject data;
    data.insert("type", classfied);
    data.insert("suffix", suffix);
    data.insert("image", QString(image));
    QByteArray imageInfo = QJsonDocument(data).toJson();
    dataPart.setBody(imageInfo);
    multiPart->append(dataPart);

    /* 設定頭資訊 */
    QNetworkRequest requestInfo;
    requestInfo.setUrl(QUrl(m_saveImgUrl));

    /* 傳送資料 */
    QNetworkReply *reply = m_pManager->post(requestInfo, multiPart);
    multiPart->setParent(reply);

    /* 超時定時器 */
    QElapsedTimer timer;
    timer.start();
    connect(reply, SIGNAL(finished()), this, SLOT(finished()));

    if (timeout < 0) {
        qWarning() << "timeout is error";
        return;
    }

    /* 處理響應 */
    while (timer.elapsed() < timeout) {
        QCoreApplication::processEvents();
    }
}

void PostData::postLog(QString log, int timeout){

    /* 設定頭資訊 */
    QNetworkRequest requestInfo;
    requestInfo.setUrl(QUrl(m_networkUrl));
    requestInfo.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    QByteArray logInfo = QString(log).toUtf8();

    /* 傳送資料 */
    QNetworkReply *reply = m_pManager->post(requestInfo, "log=" + logInfo);

    /* 新增事件迴圈機制,返回後再執行後面的 */
    QEventLoop eventLoop;
    connect(reply, SIGNAL(finished()), &eventLoop, SLOT(quit()));
   QTimer timer;
    timer.setInterval(timeout);
    timer.setSingleShot(true);
    timer.start();
    eventLoop.exec();

    /* 處理響應 */
    if (timer.isActive()) {
        /* 錯誤處理 */
        if (reply->error() == QNetworkReply::NoError) {
            qWarning() << "request protobufHttp success";
        } else {
            qWarning() <<"request protobufHttp handle errors here";
            QVariant statusCodeV = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
            /* statusCodeV是HTTP伺服器的相應碼,reply->error()是Qt定義的錯誤碼,可以參考QT的文件 */
            qWarning() << "status code: " << statusCodeV.toInt();
            qWarning() << "status code: " << (int)reply->error();
        }
        /* 請求收到的結果 */
        QByteArray responseByte = reply->readAll();
        qWarning() << "response: " << responseByte;
    } else {
        disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
        reply->abort();
        qWarning() << "time out";
    }
    reply->deleteLater();
}

main.cpp

#include <QCoreApplication>
#include <QDebug>
#include <PostData.h>
#include <QByteArray>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    /* 呼叫post請求介面 */
    PostData manager;
    //QByteArray data = QByteArray::fromBase64("PHA+SGVsbG8/PC9wPg==", QByteArray::Base64Encoding);
    //manager.postImage("module", "jpg", data);
    //manager.postImage("module", "jpg", data, -1);
    //manager.postLog("log");
    manager.postLog("log",  5000);

    return a.exec();
}