Qt

Qt Http 封装

2018-12-10  本文已影响486人  半岭山人

 工作中用Qt开发项目时有用到Http协议,对Http有做一个算比较全面的封装,同时还包含对JSON格式的解析,整个模块还算可用,现写点东西留个纪念,如有需要的人也可做个参考,仅此而已。
 废话不多说,直接上代码。

#ifndef HTTP_H
#define HTTP_H

#include <QString>

#define HTTP_COMMAND_LOGIN 0
#define HTTP_COMMAND_BOOKINFO 1
#define HTTP_COMMAND_CONVERTTAG 2
#define HTTP_COMMAND_GETACCOUNTS 3
#define HTTP_COMMAND_GETWORKLOAD 4
#define HTTP_COMMAND_REGACCOUNT 5
#define HTTP_COMMAND_BORROWERINFO 8
#define HTTP_COMMAND_REGBORROWER 9

class Http
{
public:
    enum ErrorType
    {
        NoError = 0,
        ResponseError,
        NetworkError
    };

    Http();

    static void setAddr(QString addr)
    { m_addr = addr; }
    static QByteArray Post(QByteArray,
                           bool isAsync = true);
    static QByteArray Get(QByteArray,
                          bool isAsync = true);
    static bool DownloadFile(QByteArray,
                             QObject* receiver);
    static QByteArray UploadFile(const QString &filePath,
                                 QByteArray,
                                 QObject *sender);
    static int DoubanBookInfo(const QString& par1,
                              const QString& par2,
                              int& code);
    static int GetBookInfo(const QString& barcode,
                           const QString& tag,
                           const QString& keyword,
                           QList<BookInfo>& books,
                           int& code);
    static int StartDownloadFile(const QString& uid,
                                 const QString& token,
                                 const int& keyid,
                                 QObject* receiver,
                                 int& code);
    static int StartUploadFile(const QString& uid,
                               const QString& token,
                               const QString& filePath,
                               const int& index,
                               const int& total,
                               const QString& filetype,
                               const QString& desc,
                               QObject *sender,
                               int& code);
private:
    static QString m_addr;
    static QString m_dest;
};

#endif // HTTP_H
#include "http.h"
#include <QHttpMultiPart>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QEventLoop>
#include <QMessageBox>
#include <QJsonObject>
#include <QJsonDocument>
#include <QJsonValue>
#include <QJsonArray>
#include "qdebug.h"
#include <QFileInfo>
QString Http::m_dest;
QString Http::m_addr;
Http::Http()
{

}
QByteArray Http::Post(QByteArray data,
                      bool isAsync)
{
    QNetworkAccessManager manager;
    QEventLoop eventLoop;
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
    QNetworkRequest request;
    request.setUrl(QUrl(m_dest));
    LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") + QString("Url: %1, Request: %2").arg(m_dest).arg(QString(data)));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=utf-8");

    QNetworkReply *reply = manager.post(request, data);
    if(!isAsync)
        eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    else
        eventLoop.exec();
    QByteArray response;
    if (reply->error() == QNetworkReply::NoError) {
        response = reply->readAll();
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Response: %1").arg(QString(response)));
    } else {
        //failure
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Network Ex: %1").arg(reply->errorString()));
    }
    reply->deleteLater();
    return response;
}
QByteArray Http::Get(QByteArray data,
                     bool isAsync)
{
    QNetworkAccessManager manager;
    QEventLoop eventLoop;
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
    QNetworkRequest request;
    if(data.isEmpty())
        request.setUrl(QUrl(m_dest));
    else
        request.setUrl(QUrl(m_dest + "?" + data));
    LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") + QString("Url: %1, Request: %2").arg(m_dest).arg(QString(data)));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=utf-8");
    QNetworkReply *reply = manager.get(request);
    if(!isAsync)
        eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    else
        eventLoop.exec();
    QByteArray response;
    if (reply->error() == QNetworkReply::NoError) {
        response = reply->readAll();
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Response: %1").arg(QString(response)));
    } else {
        //failure
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Network Ex: %1").arg(reply->errorString()));
    }
    reply->deleteLater();
    return response;
}

bool Http::DownloadFile(QByteArray data,
                        QObject *receiver)
{
    QNetworkAccessManager manager;
    QEventLoop eventLoop;
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
    QNetworkRequest request;
    if(data.isEmpty())
        request.setUrl(QUrl(m_dest));
    else
        request.setUrl(QUrl(m_dest + "?" + data));
    LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") + QString("Url: %1, Request: %2").arg(m_dest).arg(QString(data)));
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded; charset=utf-8");
    QNetworkReply *reply = manager.get(request);
    DownloadFileDialog *dialog = qobject_cast<DownloadFileDialog *>(receiver);
    if(dialog != NULL)
    {
        dialog->setNetworkReply(reply);
        QObject::connect(reply, SIGNAL(downloadProgress(qint64,qint64)), dialog, SLOT(downloadProgress(qint64,qint64)));
        QObject::connect(reply, SIGNAL(readyRead()), dialog, SLOT(downloadRead()));
    }
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    bool bRet = false;
    if (reply->error() == QNetworkReply::NoError) {
        bRet = true;
    } else {
        //failure
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Network Ex (download fail): %1").arg(reply->errorString()));
    }
    reply->deleteLater();
    return bRet;
}

QByteArray Http::UploadFile(const QString &filePath,
                            QByteArray data,
                            QObject *sender)
{
    QByteArray response;
    QNetworkAccessManager manager;
    QEventLoop eventLoop;
    QObject::connect(&manager, SIGNAL(finished(QNetworkReply*)), &eventLoop, SLOT(quit()));
    QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
    QHttpPart filePart;
    QFileInfo file_info(filePath);
    QString suffix = file_info.suffix();
    if(suffix.compare("png", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/png; charset=utf-8"));
    }
    else if(suffix.compare("jpg", Qt::CaseInsensitive) == 0 || suffix.compare("jpeg", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg; charset=utf-8"));
    }
    else if(suffix.compare("gif", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/gif; charset=utf-8"));
    }
    else if(suffix.compare("apk", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/vnd.android.package-archive; charset=utf-8"));
    }
    else if(suffix.compare("mp3", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("audio/mp3; charset=utf-8"));
    }
    else if(suffix.compare("mp4", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("video/mpeg4; charset=utf-8"));
    }
    else if(suffix.compare("avi", Qt::CaseInsensitive) == 0)
    {
        filePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("video/avi; charset=utf-8"));
    }
    else
    {
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("File(%1) format unknown").arg(filePath));
        return response;
    }
    filePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + file_info.fileName() + "\"; filename=\"" + file_info.fileName() + "\""));
    QFile *file = new QFile(filePath);
    file->open(QIODevice::ReadOnly);
    filePart.setBodyDevice(file);
    file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
    multiPart->append(filePart);
    QNetworkRequest request;
    request.setUrl(QUrl(m_dest + "?" + data));
    LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
        QString("Url: %1, Request: %2").arg(m_dest).arg(QString(data)));
    QNetworkReply *reply = manager.post(request, multiPart);
    UploadFileDialog *dialog = qobject_cast<UploadFileDialog *>(sender);
    if(dialog != NULL)
    {
        QObject::connect(reply, SIGNAL(uploadProgress(qint64,qint64)), dialog, SLOT(uploadProgress(qint64,qint64)));
    }
    multiPart->setParent(reply); // delete the multiPart with the reply
    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
    if (reply->error() == QNetworkReply::NoError) {
        response = reply->readAll();
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Response: %1").arg(QString(response)));
    } else {
        //failure
        LogEvent::postLog(LogEvent::LOG_DEBUG, QString(__FUNCTION__).append("() - ") +
            QString("Network Ex: %1").arg(reply->errorString()));
    }
    reply->deleteLater();
    return response;
}
int Http::GetBookInfo(const QString &barcode,
                      const QString &tag,
                      const QString &keyword,
                      QList<BookInfo>& books,
                      int &code)
{
    code = ErrorCode::NetworkException;
    QString url = "/Api/Book/Info";
    m_dest = m_addr + url;
    int ret = NetworkError;
    QJsonObject json;
    json.insert("barcode", barcode);
    json.insert("tag", tag);
    json.insert("keyword", keyword);
    QJsonDocument document;
    document.setObject(json);
    QByteArray response = Post(document.toJson(QJsonDocument::Compact), false);
    if(!response.isEmpty())
    {
        ret = NoError;
        QJsonParseError jsonError;
        QJsonDocument parseDoc = QJsonDocument::fromJson(response, &jsonError);  // 转化为 JSON 文档
        if (!parseDoc.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
            /// JSON 文档为对象
            if (parseDoc.isObject()) {
                QJsonObject object = parseDoc.object();
                if (object.contains("code")) {
                    QJsonValue value = object.value("code");
                    if (value.isDouble()) {
                        code = value.toVariant().toInt();
                    }
                }
                if (object.contains("info")) {
                    QJsonValue value = object.value("info");
                    if(value.isArray()){
                        QJsonArray array = value.toArray();
                        int size = array.size();
                        for(int i = 0; i < size; i++){
                            BookInfo book;
                            QJsonValue value = array.at(i);
                            if (value.isObject()) {
                                QJsonObject object= value.toObject();
                                if (object.contains("keyid")) {
                                    QJsonValue value = object.value("keyid");
                                    if (value.isDouble()) {
                                        book.keyid = value.toVariant().toInt();
                                    }
                                }
                                if (object.contains("type")) {
                                    QJsonValue value = object.value("type");
                                    if(value.isString()){
                                        book.type = value.toString();
                                    }
                                }
                                books.append(book);
                            }
                        }
                    }
                }
            }
        }
    }
    return ret;
}
int Http::DoubanBookInfo(const QString &par1,
                         const QString &par2,   
                         int &code)
{
    code = ErrorCode::NetworkException;
    int ret = NetworkError;
    QString url = "/Api/Book/Info/Douban";
    m_dest = m_addr + url;
    QByteArray form;
    form.append("par1=" + par1 + "&");
    form.append("par2=" + par2);
    QByteArray response = Get(form, false);
    if(!response.isEmpty())
    {
        ret = NoError;
        QJsonParseError jsonError;
        QJsonDocument parseDoc = QJsonDocument::fromJson(response, &jsonError);  // 转化为 JSON 文档
        if (!parseDoc.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
            /// JSON 文档为对象
            if (parseDoc.isObject()) {
                QJsonObject object = parseDoc.object();
                if (object.contains("code")) {
                    QJsonValue value = object.value("code");
                    if (value.isDouble()) {
                        code = value.toVariant().toInt();
                    }
                }
            }
        }
    }
    return ret;
}
int Http::StartDownloadFile(const QString &uid,
                            const QString &token,
                            const int &keyid,
                            QObject* receiver,
                            int &code)
{
    code = ErrorCode::NetworkException;
    int ret = NetworkError;
    QString url = "/Api/User/File/Download/Media";
    m_dest = m_addr + url;
    QByteArray form;
    form.append("keyid=" + QString::number(keyid) + "&");
    form.append("uid=" + uid + "&");
    form.append("token=" + token);
    bool bRet = DownloadFile(form, receiver);
    if(bRet)
    {
        code = ErrorCode::Success;
        ret = NoError;
    }
    return ret;
}

int Http::StartUploadFile(const QString &uid,
                          const QString &token,
                          const QString &filePath,
                          const int &index,
                          const int &total,
                          const QString &filetype,
                          const QString &desc,
                          QObject *sender,
                          int &code)
{
    code = ErrorCode::NetworkException;
    int ret = NetworkError;
    QString url = "/Api/User/File/Upload";
    m_dest = m_addr + url;
    QFileInfo file_info(filePath);
    QByteArray form;
    form.append("uid=" + uid + "&");
    form.append("token=" + token + "&");
    form.append("fileName=" + file_info.fileName() + "&");
    form.append("index=" + QString::number(index) + "&");
    form.append("total=" + QString::number(total) + "&");
    form.append("filetype=" + filetype + "&");
    form.append("desc=" + desc);
    QByteArray response = UploadFile(filePath, form, sender);
    if(!response.isEmpty())
    {
        ret = NoError;
        QJsonParseError jsonError;
        QJsonDocument parseDoc = QJsonDocument::fromJson(response, &jsonError);  // 转化为 JSON 文档
        if (!parseDoc.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
            /// JSON 文档为对象
            if (parseDoc.isObject()) {
                QJsonObject object = parseDoc.object();
                if (object.contains("code")) {
                    QJsonValue value = object.value("code");
                    if (value.isDouble()) {
                        code = value.toVariant().toInt();
                    }
                }
            }
        }
    }
    return ret;
}
//图书信息
typedef struct _BookInfo
{
    int         keyid;
    QString     type;

    _BookInfo()
    {
        keyid = -1;
        type = "";
    }
}BookInfo;

class ErrorCode
{
public:
    enum Code
    {
        Success = 0,
        Failed = 10001,
        InvalidMessage = 10003,
        UpdateFailed = 10005,
        NetworkException
    };
};
    //1.设置网络地址
    Http::setAddr("http://XXX.com");
    //2.调用具体函数
    QString keyword("");
    QString barcode("");
    QString tag("");
    QList<BookInfo> m_books;
    int code;
    Http::GetBookInfo(barcode,
                      tag,
                      keyword,
                      m_books,
                      code);
    if(code != ErrorCode::Success)
    {
        if(!errorMessage.isEmpty())
            QMessageBox::warning(this, tr("Warning"), "", tr("Ok"));
        return;
    }
    
    // 更新界面
    foreach(BookInfo book, m_books)
    {
        ///
    }
1. QEventLoop用于实现同步等待网络响应,如果使用QEventLoop::ExcludeUserInputEvents会导致界面无法响应输入事件,出现类似卡死现象,在调用自己封装的网络接口等待后台响应时,如果不想界面还可以被乱点,可以使用eventLoop.exec(QEventLoop::ExcludeUserInputEvents)来处理,期间还可以弹出加载提示窗口来提醒。
2. LogEvent::postLog(),是调试信息模块,用于输出自定义Log,麻烦自行删除或换成自己的调试信息接口。
3. DownloadFileDialog和UploadFileDialog都是为了获取上传/下载状态信息,可以换成自己的窗口类。
4. 本文分享模块是项目里临时抽取出来的,如果有内容遗漏导致编译失败,可以留言提醒。

喜者留痕,厌者无视

上一篇下一篇

猜你喜欢

热点阅读