5. Content-Type 头字段
设置“Content-Type”头字段的目的是为了完整的描述主体(body)中数据的内容。这样,接收代理就可以挑选出适当的代理或机制,来向用户呈现数据内容,或以适当的方式处理数据。这个字段值被称为“媒体类型”(media type)。
历史注释:“Content-Type”头字段最初是在RFC1049中定义的。RFC1049中使用的是相对简单的,不强大的语法,但是在很大程度上与本文档所定义的机制相兼容。
“Content-Type”头字段通过指定媒体类型及子类型的标识符来说明实体主体(body of an entity)中数据的原始类型,而且它还会为一些特别的媒体类型提供辅助信息。在媒体类型及子类型名称之后,本字段中的其余部分均为参数,它们以“属性=值”的形式给出,至于这些参数是按什么顺序给出的,则并不重要。
总的来说,顶层的媒体类型被用来声明数据的一般类型,而子类型则指明了数据的细节格式。因此,媒体类型“image/xyz”足以使用户代理知道,接收的数据是一个图像,哪怕这个用户代理并不知道这种特殊的图像类型:“xyz”。因此,这类信息可以被用来决定是否向用户显示一种拥有不能识别的子类型的原始数据――此操作对于拥有不可识别子类型的文本内容来说是合理的,但不适用于图像(image)和音频(audio)类型的数据。由于这个原因,文本、图像、音频和视频的子类型都不能包含有不同类型的嵌入信息。这种复合的格式应该由类型“multipart”和“application”所描述。
参数是媒体子类型的修饰成份,而不会影响内容的性质。一组有意义的参数依赖于媒体类型及子类型。大部分的参数只与某单一的子类型相关联。然而,一个顶级的媒体类型可以定义一些与其中的任何子类型都关联的参数。对于所涉及到的内容类型(content type)或子类型(subtype)来说,参数可能是必须的,也可能是可选的。MIME的实现过程中必须忽略所有不能识别的参数。
例如,“charset”参数可适用于“text”类型中的任何子类型,而“boundary”参数则是“multipart”类型中所有子类型所必须的。
不存在适用于所有媒体类型的全局参数。真正的全局机制是通过在MIME原型中定义“Content-*”头字段而提出的。
在RFC2046中定义了最初的七个顶级媒体类型。其中的五个是不连续的类型,它们的内容是MIME处理过程所不关心的。另外的两个类型是合成的,它们的内容需要MIME处理器进行额外的处理。
这组顶级的媒体类型(media type)已被完全定义。希望在对这组媒体类型进行扩充的时候,只是扩充初始类型中的子类型。将来,只可以在扩展本标准的情况下,才能定义更多的顶级媒体类型。无论任何原因,如果需要使用另一个顶级类型,那么这个类型的名称必须以“X-”开头,以表示它是一个非标准的状态,以避免今后与官方定义的名称冲突。
5.1 Content-Type头字段的语法
用一种扩充的BNF符号定义“Content-Type”头字段,如下:
content := "Content-Type" ":" type "/" subtype
*(";" parameter)
; 匹配媒体类型或子类型时,是大小写无关的
type := discrete-type / composite-type
discrete-type := "text" / "image" / "audio" / "video" /
"application" / extension-token
composite-type := "message" / "multipart" / extension-token
extension-token := ietf-token / x-token
ietf-token := <An extension token defined by a
standards-track RFC and registered
with IANA.>
x-token := <The two characters "X-" or "x-" followed, with
no intervening white space, by any token>
subtype := extension-token / iana-token
iana-token := <A publicly-defined extension token. Tokens
of this form must be registered with IANA
as specified in RFC 2048.>
parameter := attribute "=" value
attribute := token
; 匹配属性( attributes)时,
; 总是大小写无关的
value := token / quoted-string
token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
or tspecials>
tspecials := "(" / ")" / "<" / ">" / "@" /
"," / ";" / ":" / "\" / <">
"/" / "[" / "]" / "?" / "="
; Must be in quoted-string,
; to use within parameter values
注意,对“tspecials”的定义与RFC822中对“specials”的定义是几乎一样的,只是新增了三个字符:“/”、“?”、“=”,又去掉了一个字符:“.”。
还要注意到,对子类型(subtype)的定义是强制性的――子类型不可以被Content-Type字段所忽略,因此,也就不存在缺省的子类型(subtype)。
类型、子类型、参数名称都是大小写无关的。例如:“TEXT”、“Text”和“TeXt”表示相同的顶级媒体类型。参数值通常都是大小写相关的,但是一些时候也被定义为大小写无关的形式,这依赖于具体的应用。(例如,multipart boundary就是大小写相关的、而“access-type”则是大小写无关的)
注意一个用引号括起来的参数值中不包括引号,这就是说,一个被引号括起来的字符串中,引号是不包括在参数值中的,但这仅限于使用引号确定参数值界线的情况下。另外,格式与RFC822规则一致的注释也允许出现在这个字段中,因些,以下两种形式是完全等价的:
Content-type: text/plain; charset=us-ascii (Plain text)
Content-type: text/plain; charset="us-ascii"
除了这些句法之外,对构成子类型名称的唯一句法约束是它们在使用中不可以相互冲突。这就是说,不可以有两个不同的团体使用“Content-Type: application/foobar”来表示两种不同东西。定义一个媒体子类型的过程,并不受限制:只需要公布这些类型的定义,并使用它们即可。因此,两种广泛接受的定义媒体子类型的机制如下:
(1) 私有值(以“X-”开头的名称)可以在两个协同工作的代理之间双向的定义,而不需要外部的注册或标准化。这种值不可以被注册或制定为标准。
(2) 可以向IANA注册新的标准,如RFC2048中描述的情况。
这组文档中的第二篇:RFC2046定义了媒体类型的初始集合。
5.2 Content-Type的缺省值
没有“Content-Type”头字段的RFC822消息被默认为是US-ASCII字符集、纯文本类型的内容。它可以被精确的描述为:
Content-type: text/plain; charset=us-ascii
这个缺省值是在没有指定“Content-Type”头字段时而使用的。而且,在遇到句法错误的“Content-Type”头字段时,也会使用这个缺省值。当消息中存在“MIME-Version”头字段,而缺少“Content-Type”头字段时,接收方的用户代理也可以假定发送者所发送的是US-ASCII字符集的纯文本内容。在没有“MIME-Version”头字段或有错误语法的“Content-Type”头字段时,仍然可以假定其内容是US-ASCII字符集的纯文本,但是这可能不是发送者的本意。