内容简介:传统通过 HTTP 表单的方式来上传文件在 Web 中实现是非常简单的,一个表单中加几个域填写上对应的内容提交就可以了,但如果通过 Qt 来实现就相对麻烦一点,不过我都总结好了代码,直接使用就可以了。Qt 官方基于头文件:
传统通过 HTTP 表单的方式来上传文件在 Web 中实现是非常简单的,一个表单中加几个域填写上对应的内容提交就可以了,但如果通过 Qt 来实现就相对麻烦一点,不过我都总结好了代码,直接使用就可以了。
需要用到的模块
- QNetworkAccessManager 用来发起 GET/POST 请求
- QNetworkReply 用来描述响应信息
- QHttpMultiPart 用来模拟表单域
- QNetworkRequest 用来构建请求地址等信息
Qt 官方简单例子
Qt 官方基于 QHttpMultiPart
的简单例子: https://doc.qt.io/archives/qt-4.8/qhttpmultipart.html
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
textPart.setBody("my text");
QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image\""));
QFile *file = new QFile("image.jpg");
file->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(file);
file->setParent(multiPart); // we cannot delete the file now, so delete it with the multiPart
multiPart->append(textPart);
multiPart->append(imagePart);
QUrl url("http://my.server.tld");
QNetworkRequest request(url);
QNetworkAccessManager manager;
QNetworkReply *reply = manager.post(request, multiPart);
multiPart->setParent(reply); // delete the multiPart with the reply
// here connect signals etc.
封装后的类
头文件:
#ifndef HTTPUP_LOADER_H
#define HTTPUP_LOADER_H
#include <QObject>
#include <QString>
#include <QByteArray>
#include <QtNetwork/QHttpPart>
#include <QtNetwork/QHttpMultiPart>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
#include <QtNetwork/QNetworkAccessManager>
class HttpUploader : public QObject
{
Q_OBJECT
public:
HttpUploader(const QString& url, QObject* receiver);
~HttpUploader();
void SetPostURL(const QString& url) { url_ = url; }
QString GetPostURL() { return url_; }
bool AddTextField(const QString& key, const QByteArray& value);
bool AddFileField(const QString& key, const QString& file_path);
bool PostRequest();
QNetworkAccessManager* GetNetworkManager() { return net_manager_; }
signals:
private:
QObject* receiver_;
QString url_;
QByteArray post_content_;
// http upload
QNetworkAccessManager* net_manager_ = nullptr;
QNetworkReply* net_reply_ = nullptr;
QHttpMultiPart* multi_part_ = nullptr;
};
#endif // HTTPUP_LOADER_H
实现文件
#include <QFile>
#include <QUuid>
#include <QFileInfo>
#include "http_uploader.h"
HttpUploader::HttpUploader(const QString& url, QObject* receiver)
: receiver_(receiver)
, url_(url)
, post_content_(QByteArray())
{
multi_part_ = new QHttpMultiPart(QHttpMultiPart::FormDataType);
net_manager_ = new QNetworkAccessManager(this);
connect(net_manager_, SIGNAL(finished(QNetworkReply*)), receiver, SLOT(onNetworkFinished(QNetworkReply*)));
}
HttpUploader::~HttpUploader()
{
if (multi_part_ != nullptr)
{
delete multi_part_;
}
if (net_manager_ != nullptr)
{
delete net_manager_;
}
}
bool HttpUploader::AddTextField(const QString &key, const QByteArray &value)
{
QHttpPart text_part;
text_part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + key + "\""));
text_part.setBody(value);
multi_part_->append(text_part);
return true;
}
bool HttpUploader::AddFileField(const QString &key, const QString& file_path)
{
QHttpPart file_part;
QFileInfo upload_file_info(file_path);
file_part.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream"));
file_part.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"" + key + "\"; filename=\"" + upload_file_info.fileName() + "\""));
QFile *file = new QFile(file_path);
file->open(QIODevice::ReadOnly);
file->setParent(multi_part_);
file_part.setBodyDevice(file);
multi_part_->append(file_part);
return true;
}
bool HttpUploader::PostRequest()
{
QNetworkRequest request = QNetworkRequest(QUrl(url_));
net_reply_ = net_manager_->post(request, multi_part_);
multi_part_->setParent(net_reply_); // delete the multiPart with the reply
connect(net_reply_, SIGNAL(finished()), receiver_, SLOT(onReplyFinished()));
connect(net_reply_, SIGNAL(uploadProgress(qint64, qint64)), receiver_, SLOT(onUploadProgress(qint64, qint64)));
return true;
}
外部调用时,像下面这样调用就可以了
HttpUploader* uploader_ = new HttpUploader(report_url_, this);
uploader_->AddTextField("userId", report_id_.toUtf8());
uploader_->AddTextField("reportContent", comment_.toUtf8());
uploader_->AddFileField("logFile", report_zip_file_);
...
uploader_->PostRequest();
在 new 上传对象的指针时,第二个传递的参数是当前类的一个指针,你需要实现 onNetworkFinished
, onReplyFinished
, onUploadProgress
,来监视上传任务的进度和完成信息,当然你可以自己封装一下,上传对象仅仅提供信号,需要时在外部 connect 就可以了。onNetworkFinished 和 onReplyFinished 的区别是,onReplyFinished 槽函数对应 QNetworkReply 的 finished 信号,他仅仅通知完成了,不会携带任何参数。但是你可以通过 QNetworkReply 的实例对象来获取各种返回值信息。而 onNetworkFinished 槽函数对应的是 QNetworkAccessManager 的 finished 信号,其会携带一个 QNetworkReply 对象指针,你只需要在这里处理返回的对应错误码就可以了。
返回值处理
我使用 QNetworkAccessManager 的 finished 信号来接收完成事件,在 onNetworkFinished 函数中,我们接收到的信息是一个 reply 对象。你可以通过 reply 对象获取 HTTP 返回值:
QVariant variant = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); QDebug() << variant.toInt();
也可以打印 Qt 自由的一套返错误代码
qDebug() << reply->error(); qDebug() << reply->errorString();
如果没有错误的情况下,你可以使用 reply 对象获取返回的内容:
qDebug() << reply->readAll();
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Seasoned Schemer
Daniel P. Friedman、Matthias Felleisen / The MIT Press / 1995-12-21 / USD 38.00
drawings by Duane Bibbyforeword and afterword by Guy L. Steele Jr.The notion that "thinking about computing is one of the most exciting things the human mind can do" sets both The Little Schemer (form......一起来看看 《The Seasoned Schemer》 这本书的介绍吧!
CSS 压缩/解压工具
在线压缩/解压 CSS 代码
RGB转16进制工具
RGB HEX 互转工具