前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Qt 模拟 HTTP 表单提交文字或文件到服务器

Qt 模拟 HTTP 表单提交文字或文件到服务器

作者头像
我与梦想有个约会
发布2023-10-21 15:20:29
3000
发布2023-10-21 15:20:29
举报
文章被收录于专栏:jiajia_dengjiajia_deng

传统通过 HTTP 表单的方式来上传文件在 Web 中实现是非常简单的,一个表单中加几个域填写上对应的内容提交就可以了,但如果通过 Qt 来实现就相对麻烦一点,不过我都总结好了代码,直接使用就可以了。

需要用到的模块

  • QNetworkAccessManager 用来发起 GET/POST 请求
  • QNetworkReply 用来描述响应信息
  • QHttpMultiPart 用来模拟表单域
  • QNetworkRequest 用来构建请求地址等信息

Qt 官方简单例子

Qt 官方基于 QHttpMultiPart 的简单例子:https://doc.qt.io/archives/qt-4.8/qhttpmultipart.html

代码语言:javascript
复制
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.

封装后的类

头文件:

代码语言:javascript
复制
#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

实现文件

代码语言:javascript
复制
#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;
}

外部调用时,像下面这样调用就可以了

代码语言:javascript
复制
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 上传对象的指针时,第二个传递的参数是当前类的一个指针,你需要实现 onNetworkFinishedonReplyFinishedonUploadProgress,来监视上传任务的进度和完成信息,当然你可以自己封装一下,上传对象仅仅提供信号,需要时在外部 connect 就可以了。onNetworkFinished 和 onReplyFinished 的区别是,onReplyFinished 槽函数对应 QNetworkReply 的 finished 信号,他仅仅通知完成了,不会携带任何参数。但是你可以通过 QNetworkReply 的实例对象来获取各种返回值信息。而 onNetworkFinished 槽函数对应的是 QNetworkAccessManager 的 finished 信号,其会携带一个 QNetworkReply 对象指针,你只需要在这里处理返回的对应错误码就可以了。

返回值处理

我使用 QNetworkAccessManager 的 finished 信号来接收完成事件,在 onNetworkFinished 函数中,我们接收到的信息是一个 reply 对象。你可以通过 reply 对象获取 HTTP 返回值:

代码语言:javascript
复制
QVariant variant = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute);
QDebug() << variant.toInt();

也可以打印 Qt 自由的一套返错误代码

代码语言:javascript
复制
qDebug() << reply->error();
qDebug() << reply->errorString();

如果没有错误的情况下,你可以使用 reply 对象获取返回的内容:

代码语言:javascript
复制
qDebug() << reply->readAll();
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-05-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需要用到的模块
  • Qt 官方简单例子
  • 封装后的类
  • 返回值处理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档