美文网首页Qt
Qt Http 封装

Qt Http 封装

作者: 半岭山人 | 来源:发表于2018-12-10 14:37 被阅读486次

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

    • http.h
    #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
    
    • http.cpp
    #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. 本文分享模块是项目里临时抽取出来的,如果有内容遗漏导致编译失败,可以留言提醒。
    

    喜者留痕,厌者无视

    相关文章

      网友评论

        本文标题:Qt Http 封装

        本文链接:https://www.haomeiwen.com/subject/tzlrhqtx.html