工作中用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. 本文分享模块是项目里临时抽取出来的,如果有内容遗漏导致编译失败,可以留言提醒。
喜者留痕,厌者无视
网友评论