对http content-type 和 multipart的理解

1996年的rfc2045 定义了MIME(
Multipurpose Internet Mail Extensions)协议,最初的目的是为了扩展在邮件中传输的数据类型。传输ascii字节以外的信息,后来在HTTP协议中也得到了应用。

MIME使用Content-Type字段来确定在传递的数据类型,在rfc中描述如下:

    The purpose of the Content-Type field is to describe the data
   contained in the body fully enough that the receiving user agent can
   pick an appropriate agent or mechanism to present the data to the
   user, or otherwise deal with the data in an appropriate manner. The
   value in this field is called a media type.

该字段的目的是为了完整的描述body中的数据,以便于接收方可以选择一个合适的实体或者机制来呈现body中的数据,或者以一种合适的方式来处理body中的数据。这个值被叫做媒体类型。协议的规定就是为了约定好前端和后端之间以http协议交互时的默认处理规则。

我理解的协议的规定是为了让不同厂家的浏览器,不同厂家的web服务都基于标准的协议来实现,才可以让浏览器上能按照协议约定的内容进行展示,并能充分考虑兼容的场景。比如 image/jpeg 就展示图片,
audio类型就调用对应的解析器来播放音乐。

content-type字段在http的响应头中的格式如下

content-type:text/html; charset=UTF-8

type 区分为 discrete-type 离散类型和 composite-type 聚合类型。常见的离散和复合类型如下:

discrete-type := "text" / "image" / "audio" / "video" /
                      "application" / extension-token
composite-type := "message" / "multipart" / extension-token

rfc2046 中区分了两大类媒体类型,一种是独立的媒体类型,包括了文本类型,图片类型,音频类型,视频类型和应用类型等。另一种是复合的媒体类型,也就是我们所知的multipart类型。multipart类型在5.1节中有明确定义,是在一个http返回中包含了多种媒体类型,不同媒体类型的数据之间以boundary的形式分割。如下为RFC2046中对于 Multipart Media Type的定义。

   In the case of multipart entities, in which one or more different
   sets of data are combined in a single body, a "multipart" media type
   field must appear in the entity's header.  The body must then contain
   one or more body parts, each preceded by a boundary delimiter line,
   and the last one followed by a closing boundary delimiter line.
   After its boundary delimiter line, each body part then consists of a
   header area, a blank line, and a body area.  Thus a body part is
   similar to an RFC 822 message in syntax, but different in meaning.

multipart包含如下常见的子类型:

  • multipart/alternative [rfc1521]
    • 表示同样的信息,以不同的格式或者表现形式在body的多个parts中返回,一般而言在body中的顺序为按复杂程度递增。比如一份word文档,可能以word文档格式,以及富文本格式,以及纯文本格式返回,纯文本格式就会出现在http响应body的第一个部分。这对于不同的客户端,可能支持或者不支持对应格式化的客户端,就都能进行展示,服务端返回数据拥有更好的兼容性。
  • multipart/byteranges [rfc2068]
    • 字节范围类型的每一个parts包含独立的 Content-Type and Content-Range 字段,这主要是为了传输二进制数据,同时基于Content-Range字段指定每一个parts的二进制数据的长度和偏移量。
  • multipart/form-data [rfc1867]
    • 该字段是为了让请求方以一种统一的形式实现文件上传的请求,同时提供一种兼容MIME的方式呈现文件上传的响应。
  • multipart/mixed [rfc1521]
    • mixed应该属于最常用的子类型,当body的每一个parts是独立的时候,且需要以一个特定的顺序被聚合在一起的时候,就使用这种类型。同时当一个UserAgent客户端无法识别multipart子类型的时候,就会默认以multipart/mixed的形式对待。
    • x-mixed-replaced
      • 表示每一个数据块都会替代前一个数据块。
  • multipart/related [rfc2112]
    • 该类型用于聚合的文件类型,多个文件是聚合在一起用于表达完整的数据信息。通常会有一个“root”body类型作为起始的part。

该段参考自 https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/aa493937(v=exchg.140)

multipart的两种常见应用场景如下:
其一是 以 multipart/form-data的形式,通过http的post请求提交一个表单请求。

其二是 以multipart/mixed; 以一种混合的方式来返回多个独立的数据块。

Content-type: multipart/mixed;boundary=ThisRandomString 
--ThisRandomString
Content-type: application/json;
Content-length: xxx;

{jsonbody}
--ThisRandomString
Content-type: application/json;
Content-length: xxx;

{jsonbody}
--ThisRandomString

如果在自己实现httpclient进行解析时,在解析过程中需要提取http返回头中的boundary。基于boundary进行每一块的拆分,然后对拆分后的各个part中共的body的内容逐次进行解析。但要注意content通常以回调的形式返回,一次回调返回的内容是否为完整的part是不确定的,可能不足,也可能包含了多个part。故而需要以类似状态机的形式进行解析。

除了Content-type之外,MIME头部还包括Content-Transfer-Encoding和Content-Disposion。

Content-Transfer-Encoding的应用场景主要在于部分旧的消息转发的实体的实现只能处理US-ASCII字符,即7bit ascii字符。故而为了能够让这些实体正常的传输一些更丰富的数据,需要对这些数据进行一定程度的编码,比如base64 和 quoted-printable都是 MIME定义的合适的编码格式,在服务端回复消息时定义了对应的编码,在客户端识别到传输的数据经过了这些编码,则执行对应的反编码即可。

Content-Disposion 允许标记一条信息用来表示其呈现机制或者是存储方式,最常见的是 Content-Disposition: attachment 指示附件下载时建议的文件名。

但是一般情况下我们实现协议的方式不一定标准的,所以只有对应的app能够解析,而浏览器实际上是无法解析的。可以参考协议的定义修改web服务器的返回实现,来查看浏览器对结果的解析。

参考链接:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types
https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/aa493937(v=exchg.140)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值