Qt之QHttpPart和QHttpMultiPart

简介: 简述HTTP 协议对 MIME 类型有详细描述,multipart/... 是单个消息头包含多个消息体的解决方案,multipart 类型对发送非文本类型非常有用。简述multipart 子类型QHttpPartQHttpMultiPart使用示例multipart 子类型首先,来看 QHttpMultiPart 中关于 multi

简述

HTTP 协议对 MIME 类型有详细描述,multipart/... 是单个消息头包含多个消息体的解决方案,multipart 类型对发送非文本类型非常有用。

multipart 子类型

首先,来看 QHttpMultiPart 中关于 multipart 子类型(subtype)的描述。

枚举 QHttpMultiPart::ContentType

RFC 2046 和其它地方描述的已知 multipart 子类型。

常量 描述
QHttpMultiPart::MixedType 0 对应于 "multipart/mixed" 子类型,意味着 body 部位是相互独立的。如 RFC 2046 所述。
QHttpMultiPart::RelatedType 1 对应于 "multipart/related" 子类型,意味着 body 部位是相互关联的。如 RFC 2387 所述。
QHttpMultiPart::FormDataType 2 对应 "multipart/form-data" 子类型,意味着 body 部位包含表单元素。如 RFC 2388 所述。
QHttpMultiPart::AlternativeType 3 对应 "multipart/alternative" 子类型,意味着 body 部位是相同信息的替代表示。如 RFC 2046 所述。

QHttpPart

QHttpPart 类拥有一个 body 部位,用于 HTTP multipart MIME消息中(由 QHttpMultiPart 表示)。一个 QHttpPart 由一个 header 块和数据块组成,彼此之间存在两个连续换行。

一个 part 例子:

Content-Type: text/plain
Content-Disposition: form-data; name="text"

here goes the body

要设置 headers,使用 setHeader() 和 setRawHeader(),他们完全类似于 QNetworkRequest::setHeader() 和 QNetworkRequest::setRawHeader()。

对于读取小数据块,使用 setBody();如果是更大数据块,例如:图像,使用 setBodyDevice()。后一种方法由于内部没有复制数据,而是直接从设备读取,所以更节省内存。这意味着,当由 QNetworkAccessManager::post() 在网络上发送包含 body 部分的 multipart 消息时,设备必须打开并且可读。

构建一个小 body 的 QHttpPart,考虑下面的代码片段(将产生上述示例中显示的数据):

QHttpPart textPart;
textPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/plain"));
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"text\""));
textPart.setBody("here goes the body");

如果要从一个设备(例如:文件)读取,可以用这种方式:

QHttpPart imagePart;
imagePart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("image/jpeg"));
imagePart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image\""));
imagePart.setRawHeader("Content-ID", "my@content.id"); // 添加任何你喜欢的 headers
QFile *file = new QFile("image.jpg");
file->open(QIODevice::ReadOnly);
imagePart.setBodyDevice(file);

注意: QHttpPart 在设置时不需要设备的所有权,所以应该在不需要的时候销毁该设备。比较好的办法是将 multipart 消息设置为设备的父对象,QHttpMultiPart 部分会有说明。

QHttpMultiPart

QHttpMultiPart 类似于一个 RFC 2046 所描述的 MIME multipart 消息,通过 HTTP 发送。

一个 multipart 消息包含任意数量的 body 部分(QHttpPart),由一个独特的 boundary 分割开来。QHttpMultiPart 的 boundary 由字符串 "boundary_.oOo._" 后面跟随机字符构造而成。并提供足够的唯一性,以确保它在每个部分内不重复。如果需要的话,boundary 仍然可以通过 setBoundary() 来设置。

例如,构造一个 multipart 消息,其包含一个文本部分,紧随其后的是一个图像部分:

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); // 现在不能删除文件,所以用 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); // 用 reply 删除 multiPart
// 这里连接信号等

使用示例

比如multipart/form-data,其实就是浏览器用表单上传文件的方式。最常见的情景:发送邮件时添加附件,通常使用表单添加,也就是用 multipart/form-data 格式上传到服务器。

例如,上传一个本地的 png 格式图片:

这里写图片描述

可以看到请求内容的类型:

Content-Type: multipart/form-data; boundary="boundary_.oOo._MTA0NzE=MjcyNDY=ODk2Ng=="

其中表单类型为 multipart/form-data,boundary 是分隔符,和请求体中的分隔符内容一致。

由于上传附件不再使用原有的 HTTP 协议,所以请求体不再以 key=value 方式发送,而使用下述方式:

分隔符
字段内容1
分隔符
字段内容2

正如上图橙色区域显示方式一样。由于我们上传了一个图片,所以字段内容表示的是图片本身的字节(看上去像是乱码)。

注意:这里只是做了一个简单的演示,并没有把附件以表单的形式上传到任何服务器。如果要实际应用,可以调用一些第三方 API 进行尝试。

目录
相关文章
fetch上传文件报错的问题(multipart: NextPart: EOF)
技术栈 后台: gin(golang) 前端: react+antd+dva 问题 前端这边使用fetch发送http请求的时候,后端解析formData报错: multipart: NextPart: EOF 分析问题 原因是上传文件太小了Content-Length数量太小了,尝试将headers里这字段的value变大,发现实际的请求依然是较小值。
5590 0
|
1月前
|
应用服务中间件 Linux
org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nes
org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nes
52 0
|
1月前
|
前端开发 JavaScript
Error_ Multipart_ Boundary not foun
Error_ Multipart_ Boundary not foun
51 0
|
8月前
|
存储 缓存 Java
【Java异常】org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet requ
【Java异常】org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet requ
126 0
|
9月前
|
定位技术
QT QHttpMultiPart上传总结
QT QHttpMultiPart上传总结
235 0
|
10月前
MULTI
MULTI
64 0
|
10月前
913 error Component name “home“ should always be multi-word vuemulti-word-component-names
913 error Component name “home“ should always be multi-word vuemulti-word-component-names
61 0
|
前端开发 Java Spring
SpringMVC处理multipart请求.
一、简述     multipart格式的数据会将一个表单拆分为多个部分(part),每个部分对应一个输入域。在一般的表单输入域中,它所对应的部分中会放置文本型数据,但是如果上传文件的话,它所对应的部分可以是二进制。
1566 0
|
消息中间件 JSON NoSQL

热门文章

最新文章