超文本传输协议-HTTP/1.1
说明
本文档规定了互联网社区的标准组协议,并需要讨论和建议以便更加完善。请参考
“互联网官方协议标准”(STD 1)来了解本协议的标准化状态。本协议不限流传发布。
版权声明
Copyright (C) The Internet Society (1999). All Rights Reserved.
摘要
超文本传输协议(HTTP)是一种为分布式,合作式,超媒体信息系统。它是一种通用的,无状态(stateless)的协议,除了应用于超文本传输外,它也可以应用于诸如名称服务器和分布对象管理系统之类的系统,这可以通过扩展它的请求方法,错误代码和报头[47]来实现。HTTP的一个特点是数据表现形式是可输入的和可协商性的,这就允许系统能被建立而独立于数据传输。
HTTP在1990年WWW全球信息刚刚起步的时候就得到了应用。本说明书详细阐述了HTTP/1.1 协议,是RFC 2068的修订版[33]。
目录(略)
1 引论
1.1 目的
超文本传输协议(HTTP)是一种为分布式,合作式,多媒体信息系统服务,面向应用层的 协议。在1990年WWW全球信息刚刚起步的时候HTTP就得到了应用。HTTP的第一个版本叫做HTTP/0.9,是一种为互联网原始数据传输服务的简单协议。由RFC 1945[6]定义的HTTP/1.0进一步完善了这个协议。它允许消息以类似MIME的格式传送,包括有关数据传输的维护信息和关于请求/响应的句法修正。但是,HTTP/1.0没有充分考虑到分层代理,缓存的作用以及对稳定连接和虚拟主机的需求。并且随着不完善的应用程序的激增,HTTP/1.0迫切需要一个新的版本,以便使两个通信应用程序能够确定彼此的真实性能。
这里规定的协议叫做擧TTP/1.1".这个协议与HTTP/1.0相比,要求更为严格,以确保各项功能得到可靠实现。
实际的信息系统除了简单的检索外,要求更多的功能性(functionality),包括查找(search),前端更新(front-end update)和注解(annotation)。HTTP允许可扩充的方法集和报头集以指示请求的目的[47]。它是建立在统一资源标识符(URI)[3]提供的地址(URL)[4]和名字(URN)上[20],以指出方法应用于哪个资源的。消息以类似于一种叫做多用途网络邮件扩展(MIME)[7] 的互联网邮件的格式传送。
HTTP也是用于用户代理之间及代理/网关到其他网络系统的通用通信协议,这样的网络系统可能由SMTP[16],NNTP[13],FTP[18],Gopher[2]和WAIS[10]协议支持。这样,HTTP允许不同的应用程序对资源进行基本的超媒体访问。
1.2 要求
本文的关键词"MUST", "MUST NOT", "REQUIRED", "SHALL","SHALL NOT","SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", 和 "OPTIONAL"将由RFC 2119[34]解释。
一个应用程序如果不能满足协议提供的一个或多个MUST或REQUIRED等级的要求,是不符合要求的。一个应用程序如果满足所有MUST或REQUIRED等级以及所有SHOULD等级的要求,则被称为非条件遵循(unconditionally compliant)的;若满足所有MUST等级的要求但不能满足所有SHOULD等级的要求则被称为条件遵循的(conditionally compliant)。
1.3 术语
本说明用到了若干术语,以表示HTTP通信中各参与者和对象扮演的不同角色。
连接(connection)
为通信而在两个程序间建立的传输层虚拟电路。
消息(message)
HTTP通信中的基本单元。它由一个结构化的八比特字节序列组成,与第4章定义的句法相匹配,并通过连接得到传送。
请求(request)
一种HTTP请求消息,参看第5章的定义。
响应(response)
一种HTTP响应消息,参看第6章的定义。
资源(resource)
一种网络数据对象或服务,可以用第3.2节定义的URI指定。资源可以以多种表现方式(例如多种语言,数据格式,大小和分辨率)或者根据其它方面而而不同的表现形式。
实体(entity)
实体是请求或响应的有效承载信息。一个实体包含元信息和内容,元信息以实体头域(entity-header field)形式表示,内容以消息主体(entity-body)形式表示。在第7节详述。
表现形式 (representation)
一个响应包含的实体是由内容协商(content negotiation)决定的。如第12章所述。有可能存在一个特定的响应状态码对应多个表现形式。
内容协商(content negotiation)
当服务一个请求时选择资源的一种适当的表示形式的机制(mechanism),如第12节所述。任何响应里实体的表现形式都是可协商的(包括出错响应).
变量(variant)
在任何给定时刻,一个资源对应的表现形式(representation)可以有一个或多个(译注:一个URI请一个资源,但返回的是此资源对应的表现形式,这根据内容协商决定)。每个表现形式(representation)被称作一个变量。使用变量这个术语并不是意味着资源(resource)是必须由内容协商决定的.
客户端(client)
为发送请求建立连接的程序.
用户代理(user agent)
初始化请求的客户端程序。常见的如浏览器,编辑器,蜘蛛(网络穿越机器人),或其他的终端用户工具.
服务器(Server)
服务器是这样一个应用程序,它同意请求端的连接,并发送响应(response)。任何给定的程序都有可能既做客户端又做服务器;我们使用这些术语是为了说明特定连接中应用程序所担当的角色,而不是指通常意义上应用程序的能力。同样,任何服务器都可以基于每个请求的性质扮演源服务器,代理,网关,或者隧道等角色之一。
源服务器(Origin server)
存在资源或者资源在其上被创建的服务器(server)被成为源服务器(origin server)。
代理( Proxy)
代理是一个中间程序,它既担当客户端的角色也担当服务器的角色。代理代表客户端向服务器发送请求。客户端的请求经过代理,会在代理内部得到服务或者经过一定的转换转至其他服务器。一个代理必须能同时实现本规范中对客户端和服务器所作的要求。透明代理(transparent proxy)需要代理授权和代理识别,但不修改请求或响应。非透明代理(non-transparent proxy)需修改请求或响应,以便为用户代理(user agent)提供附加服务,附加服务包括组注释服务,媒体类型转换,协议简化,或者匿名过滤等。除非透明行为或非透明行为经明确指出,否则,HTTP代理既是透明代理也是非透明代理。
网关(gateway)
网关其实是一个服务器,扮演着代表其它服务器为客户端提供服务的中间者。与代理(proxy)不同,网关接收请求,仿佛它就是请求资源的源服务器。请求的客户端可能觉察不到它正在同网关通信。
隧道(tunnel)
隧道也是一个中间程序,它一个在两个连接之间充当盲目中继(blind relay)的中间程序。一旦隧道处于活动状态,它不能被认为是这次HTTP通信的参与者,虽然HTTP请求可能已经把它初始化了。当两端的中继连接都关闭的时候,隧道不再存在。
缓存(cache)
缓存是程序响应消息的本地存储。缓存是一个子系统,控制消息的存储、取回和删除。缓存里存放可缓存响应(cacheable response)为的是减少对将来同样请求的响应时间和网络带宽消耗。任一客户端或服务器都可能含有缓存,但高速缓存不能被一个充当隧道(tunnel)的服务器使用。
可缓存(cacheable)
我们可以说响应(response)是可缓存的,如果一个缓存(cache)为了响应后继请求而被允许存储响应消息(response message)的副本。确定HTTP响应的缓存能力(cacheability)在13节中有介绍。即使一个资源(resourse)是可缓存的,也可能存在缓存是否能利用缓存副本的约束。
第一手的(first-hand)
如果一个响应直接从源服务器或经过若干代理(proxy),并且没有不必要的延时,最后到达客户端,那么这个响应就是第一手的(first-hand)。
如果响应被源服务器(origin server)验证是有效性(validity)的,那么这个响应也同样是第一手的。
明确过期时间(explicit expiration time)
是源服务器希望实体(entity)如果没有被进一步验证(validation)就不要再被缓存(cache)返回的时间。
启发式过期时间(heuristic expiration time)
当没有明确终止时间(explicit expiration time)可利用时,由缓存所指定的终止时间.
年龄(age)
一个响应的年龄是从被源服务器发送或被源服务器成功确认的时间点到现在的时间。
保鲜寿命(freshness lifetime)
一个响应产生的时间点到过期时间点之间的长度。
保鲜(Fresh)
如果一个响应的年龄还没有超过保鲜寿命(freshness lifetime),它就是保鲜的.
陈旧(Stale)
一个响应的年龄已经超过了它的保鲜寿命(freshness lifetime),就是陈旧的.
语义透明(semantically transparent)
缓存(cache)可能会以一种语意透明(semantically transparent)的方式工作。这时,对于一个特定的响应,使用缓存既不会对请求客户端产生影响也不会对源服务器产生影响,缓存的使用只是为了提高性能。当缓存(cache)具有语意透明性时,客户端从缓存接收的响应跟直接从源服务器接收的响应完全一致(除了使用hop-by-hop头域)。
验证器(Validator)
验证器其实是协议元素(例如:实体头(entity tag)或最后更改时间(last-modified time)等),这些协议元素被用于识别缓存里保存的数据(即缓存项)是否是源服务器的实体的副本。
上游/下游(upstream/downstream)
上游和下游描述了消息的流动:所有消息都从上游流到下游.
向内/向外(inbound/outbound)
向内和向外指的是消息的请求和响应路径:"向内"即"移向源服务器","向外"即"移向用户代理(user agent)".
1.4 总体操作
HTTP协议是一种请求/响应协议。 与服务器建立连接后,客户端以请求方法,URI和协议版本号,然后紧接着跟随一个类MIME(MIME-like)消息,这个类MIME消息包括请求修饰符,客户信息和可能的消息主体。服务器以一个状态行并跟随一个类MIME(MIME-like)消息响应,状态行包含消息的协议版本和成功出错的状态码,类MIME消息包含服务器信息,实体元信息,和可能的实体。HTTP和MIME之间的关系如附录19.4节所阐述。
大部分的HTTP通信是由用户代理(user agent)开始的,由应用到一个需要源服务器资源的请求构成。最简单的情形,可以经用户代理(UA)和源服务器(O)之间的单一连接(v)完成。
请求链(Request chain)--------------------- ----------à
用户代理(UA)----------------单一连接(v)--------------源服务器(O)
<---------------------------------------响应链(response chain)
当一个或多个中间者在请求/响应链中出现的时候,会出现更复杂的情形。常见的中间者有三种:代理(proxy),网关(gateway)和隧道(tunnel)。代理(proxy)是一种转发代理(a forwarding agent),它接收绝对URI(absoulute url,相对于相对url)请求,重写全部或部分消息,然后把格式化后的请求发送到URI指定的服务器上。网关是一种接收代理(receiving agent),它充当一个层(layer),这个层在服务器之上,必要时它会把请求翻译成为下层服务器的协议。隧道不改变消息而充当两个连接之间的中继点;它用于通信需要穿过中间者(如防火墙)甚至当中间者不能理解消息内容的时候。
请求链(request chain)----------------------------------------à
UA-----v-----A-----v-----B-----v-----C------------v-----------------O
<----------------------------------------响应链(response chain)
上图显示了用户代理(user agent)和源服务器之间的三个中间者(A,B和C)。整条链的请求或响应将会通过四个单独的连接。这个特性很重要,因为某些HTTP通信选项可能只能应用于与最近的非隧道邻接点的连接,只能应用于链的端点(end-point)的连接,或者能应用于此链的所有连接。图表尽管是线性的,每个参与者可能忙于多路同时通信。例如,B可以接收来自不同于A的许多客户的请求,并且/或者可以把请求转到不同于C的服务器,与此同时,它还在处理A的请求。
任何非隧道的通信成员都可能会采用一个内部缓存(cache)来处理请求。如果沿着链的通信成员对请求采用了缓存响应,请求/响应链就会大大缩短。下图阐明了一个最终请求响应链,这是在假定B拥有一个来自O(通过C)的以前请求的响应副本,但此响应尚未被UA或A缓存。
请求链(request chain)---------->
UA-----v----------A-----v-----B-----C----O
<---------响应链 (response chain)
并不是所有的响应都能有效地缓存,一些请求可能含有修饰符,这些修饰符对缓存动作有特殊的要求。缓存动作和缓存响应的HTTP行为要求将在第13节定义。
实际上,目前万维网上有多种结构和配置的缓存(cache)和代理(proxy)正在被使用。这些系统包括节省带宽的缓存代理(proxy cache),可以广播或多点传送缓存数据的系统,通过CD-ROM分配缓存数据子集的机构,等等。HTTP系统(http system)会被应用于宽带连接的企业局域网中的协作,并且可以通过PDA进行低耗无线的,断续连接的访问。HTTP1.1的宗旨是为了支持各种各样的已经部署的配置,同时引进一种协议结构,让它满足那些需要较高可靠性,即使不能达到较高可靠性的要求,也要也让它至少可以指示故障的网络应用的要求。
HTTP通信通常发生在TCP/IP连接上。默认端口是TCP 80,不过其它端口也可以使用。这并不妨碍HTTP的实现被应用于互联网(internt)或其它网的协议之上。Http仅仅期望的是一个可靠的传输(译注:HTTP一般建立在传输层协议之上);任何提供这种保证的协议都可以被使用;协议传输数据单元(transport data unit)与HTTP/1.1请求和响应的消息结构之间的映象已经超出了本说明书的范围。
大部分HTTP/1.0的实现都是针对每个请求/响应交换产生一个新的连接。而http/1.1中,一个连接可以被用于一个或更多请求/响应交换,虽然连接可能会因为各种原因中断(见第8.1节)。
2 符号习惯和一般语法
2.1 扩充的BNF(扩充的 巴科斯-诺尔范式)
本文档规定的所有机制都用两种方法描述:散文体(prose)和类似于RFC 822的扩充Backus-Naur Form(BNF)。要理解本规范,使用者需熟悉符号表示法。扩充BNF结构如下:
名字(name)=定义(definition)
名字(name)就是代表规则的名字(译注:如:CRLF,DIGIT等等都是规则名),规则名里不能包含“<”和“>”,通过等于号把规则名和规则定义(definiation)分离开。空白(white space)是有意义的,因为可以用缩进(indentation,译注:缩进就是空白,后面会讲到LWS) 把规则定义显示成多行。某些基本规则(basic rule,译注:2.2节说明基本规则的语法)使用大写字母包含在规则定义里, 你如SP,LWS,HT,CRLF,DIGIT,ALPHA,等等。尖括号可以包含在规则定义里,只要它们的存在有利于识别规则名(译注:LWS,HT等都是规则名)。
“字面文本”(“literal”)
字面文本(literal text)两边用引号。除非声明,字面文本大小写不敏感(译注:如,HEX = "A" | "B" | "C" | "D" | "E" | "F" | "a" | "b" | "c" | "d" | "e" | "f" | DIGIT 里的A,B,C,D等等都是字面文本(literal text))。
规则1 | 规则2
由竖线(“|”)分开的元素是可选的,例如,“yes | no”表示yes或no都是可接受的。
(规则1 规则2)
围在括号里的多个元素视作一个元素。所以,“(elem (foo | bar) elem)”的符合的字符串是“elem foo elem”和“elem bar elem”。
*规则
前面的字符“*”表示重复。完整的形式是“
*元素”,表示元素至少出现次,至多出现次。默认值是0和无穷大,所以"*(元素)"允许任何数值,包括零;"1*元素"至少需要一次;"1*2element"允许一次或两次。
[规则]
方括号里是任选元素;“[foo bar]”相当于“*1(foo bar)”。
N 规则
特殊的重复:“(元素)”与“*(元素)”等价;就是说,(元素)正好出现了次。这样2DIGIT是一个两位数字,3ALPHA是一个由三个字符组成的字符串。
#规则
类似于“*”,结构“#”是用来定义一系列元素的。完整的形式是#元素,表示至少个元素,至多个元素,元素之间被一个或多个逗号(“,”)以及可选的线性空白(LWS)隔开了。这就使得表示列表这样的形式变得非常容易;像
( *LWS element) *( *LWS ","*LWS element ))
就可以表示为
1#element
无论在哪里使用这个结构,空元素都是允许的,但是不计入元素出现的次数。换句话说 ,
“(element ), , (element) ”是允许的,但是仅仅视为两个元素。因此,在至少需要一个元素的地方,必须存在至少一个非空元素。默认值是0和无穷大,这样,“#element”允许任意零个或多个元素;“1# element”需要至少一个;“1#2element”允许一个或两个元素。
;注释(comment)
用分号引导注释。
隐含的(implied) *LWS
本说明书所描述的语法是基于字的。除非特别注明,线性空白可出现在任何两个相邻字之间(标记(token)或引用字符串(quoted-string)),以及相邻字和间隔符之间,这并没有改变一个域的解释。任何两个标记(token)之间必须有至少一个分割符,否则将会被理解为单一标记。
2.2基本规则 (basic rule)
下面的规则贯穿于本规范的全文,此规则描述了基本的解析结构。US-ASCII(美国信息交换标准码)编码字符集是由ANSI X3.4-1986[21]定义的。
OCTET(字节) = <任意八比特的数据序列>
CHAR = <任意ASCII字符(ascii码值从 0到127的字节)>
UPALPHA = <任意大写字母"A"..."Z">
LOALPHA = <任意小写字母"a"..."z">
ALPHA = UPALPHA | LOALPHA
DIGIT = <任意数字0,1,...9>
CTL = <任意控制字符(ascii码值从0 到 31的字节)及删除键DEL(127>
CR =
LF =
SP =
HT =
<"> =
HTTP/1.1将 CR LF 的序列定义为任何协议元素的行尾标志,但这除了实体主体(endtity-body)外(要求比较松的应用见附录19.3)。实体主体(entity-body)的行尾标志是由它的关联媒体类型定义的,如3.7节所述。
CRLF = CR LF
HTTP/1.1 的消息头域值可以折叠成多行,但紧接着的折叠行由空格(SP)或水平制表(HT)折叠标记开始。所有的线性空白(LWS)包括折叠行的折叠标记(空格SP或水平制表键HT),具有同SP一样的语义。接收者在解析域值或将消息转送到下游(downstream)之前可能会将任何线性空白(LWS)替换成单个SP(空格)。
LWS = [CRLF] 1*( SP | HT )
下面的TEXT规则仅仅适用于域内容和域值的描述,不会被消息解释器解析。TEXT里的字可以包含不仅仅是ISO-8859-1[22]里的字符集,也可以包含RFC 2047里规定的字符集。
TEXT = <除CTLs以外的任意OCTET,但包括LWS>
一个CRLF只有作为HTTP消息头域延续的一部分时才在TEXT定义里使用。
十六进制数字字符用在多个协议元素(protocol element)里。
HEX = "A" | "B" | "C" | "D" | "E" | "F"
| "a" | "b" | "c" | "d" | "e" | "f" | DIGIT
许多HTTP/1.1的消息头域值是由LWS或特殊字符分隔的字构成的。这些特殊字符必须先被包含在引用字符串(quoted string)里之后才能用于参数值(如3.6节定义)里。
token (标记) = 1*<除CTLs与分割符以外的任意 CHAR >
separators(分割符) = "(" | ")" | "<" | ">" | "@"
| "," | ";" | ":" | """ | <">
| "/" | "[" | "]" | "?" | "="
| "{" | "}" | SP | HT
通过用圆括号括起来,注释(comment)可以包含在一些HTTP头域里。注释只可以作为域定义的一部分。在其他域里,圆括号被视作域值的一部分。
comment (注释)= "(" *( ctext | quoted-pair | comment ) ")"
ctext = <除"(" 和 ")"以外的任意TEXT >
如果一个TEXT若被包含在双引号里,则当作一个字。
quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
qdtext = >
斜划线(""")可以被作为单个字符的引用机制,但是必须要在引号和注释区之内。
quoted-pair = """ CHAR
3 协议参数
3.1 HTTP版本
HTTP使用一个“.”数字模式来指明协议的版本号。协议的版本号是为了让发送端指明消息的格式和它的能力,这是为了进一步的HTTP通信,而不仅仅是获得通信的特征。协议版本是不需要修改的,当消息组件的增加不会影响通信行为或着只增加了扩展的域值。数字是递增的,当协议会因为添加一些特征而做了修改的时候。但这些变化不会影响通常的消息解析算法,但是它会给消息添加语意(semantic)并且会暗示发送者具有额外的能力。数字也是不断递增的,当协议的消息格式每次发生变化时。
HTTP消息的版本在HTTP-Version域被指明,HTTP-Version域在消息的第一行中。
HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
注意major和minor数字必须被看成两个独立整数,每个整数都可以递增,并且可以增大到大于一位数的整数,如HTTP/2.4比HTTP/2.13低,而HTTP/2.4又比HTTP/12.3低。前导0必须被接收者忽略并且不能被发送者发送。
一个应用程序发送请求或响应消息,如果请求或响应消息里的HTTP-Version是”HTTP/1.1”,那么此应用程序必须条件遵循此协议规范。最少条件遵循此规范的应用程序应该把”HTTP/1.1”包含在他们的消息里,并且对任何不兼容HTTP/1.1的消息必须这么做。关于何时发送特定的HTTP-Version值的细节,参见RFC2145。
应用程序的HTTP版本是应用程序最少条件遵循的最高HTTP版本。
代理(proxy)和网关(gateway)应用程序需要被仔细对待,当转发(forwarding)消息的协议版本不同于代理或网关应用程序的协议版本。因为消息里协议版本说明了发送者处理协议的能力,所以一个代理/网关千万不要发送一个高于该代理/网关应用程序协议版本的消息。如果代理或网关接收了一个更高版本的消息,它也必须要降低请求的版本,要么以一个错误响应,要么切换到隧道行为(tunnel behavior)。
由于自从RFC 2068[33]发布后,产生了与HTTP/1.0代理(proxy)的互操作问题,所以缓存代理(caching proxy)必须能改变请求(request),使请求能到达他们能支持的最高版本,但网关(gateway)可以这么做也可以不这么做,而tunnel不能这么做。代理(Proxy)/网关(gateway)的响应(Response)必须和请求(request)的HTTP版本的major数字相同。
注意:在HTTP版本间的转换可能包含头域(header field)的改变,而这些改变会可能会根据HTTP版本而被要求或被拒绝。
3.2 统一资源标识符(URI)
URIs的许多名字已为人所知:WWW地址,通用文档标识符,通用资源标识符[3],以及后来的统一资源定位器(URL)[4]和统一资源名称(URN)[20]。就HTTP而言,统一资源定位器只是格式化的字符串,它通过名称,地址,或任何别的特征识别资源。
3.2.1一般语法
根据使用的背景,HTTP里的URI可以表示成绝对(absoulute)形式或相对形式(相对于已知的URL)。两种形式的区别是根据这样的事实:绝对URI总是以一个方案(scheme)名作为开头,其后是一个冒号。关于URL更详尽的信息请参看"统一资源标识符(URI):一般语法和语义",RFC 2396 [42](代替了RFCs 1738 [4]和RFC 1808 [11])。本规范采用了RFC 2396里的"URI-reference","absoluteURI","relativeURI","port","host","abs_path","rel_path",和"authority"的定义格式。
HTTP协议不对URI的长度作事先的限制,服务器必须能够处理它们资源的URI,并且应该能够处理无限长度的URI,这种无效长度的URL可能会在客户端以GET形式的请求产生。服务器应该返回414状态码(此状态码代表Request-URI太长),如果服务器不能处理太长的URI的时候。
注:服务器在依赖大于255字节的URI时应谨慎,因为一些旧的客户或代理实现可能不支持这些长度。
3.2.2 http URL
通过HTTP协议,http方案(http scheme)被用于定位网络资源(resourse)的位置。本节定义了这种方案的语法和语义。
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
如果端口为空或未给出,就假定为80。语义即:已识别的资源放在服务器上,在那台主机的那个端口上监听TCP连接。这时资源的请求的URI为绝对路径(5.1.2节)。无论什么可能的时候,URL里使用IP地址都是应该避免的(参看RFC 1900 [24])。如果绝对地址(abs_path)没有出现在URL里,那么应该给出"/"。如果代理(proxy)收到一个主机(host)名,但是这个主机名不是全称的域名(fully quanlified domain name),则代理应该把它的域名加到主机名上。如果代理(proxy)接收了一个全称的域名,代理不必改变主机。
3.2.3 URI 比较
当比较两个URI是否匹配时,客户应该对整个URI比较时应该区分大小写,并且一个字节一个字节的比较。 但下面有些特殊情况:
- 一个为空或未给定的端口等同于URI-refernece(见RFC 2396)里的默认端口;
- 主机(host)名的比较必须不必分大小写;
- 方案(scheme)名的比较必须是不区分大小写的;
- 一个空绝对路径(abs_path)等同于"/"。
除了"保留(reserved)"和"不安全(unsafe)"字符集里的字符(参见RFC 2396 [42]) ,其它字符都等效于它们的"%HEXHEX"编码.
例如,以下三个URI是等同的:
http://abc.com:80/~smith/home.html
http://ABC.com/%7Esmith/home.html
http://ABC.com:/%7esmith/home.html
3.3 日期/时间格式(Date/Time Formats)
3.3.1完整日期 (Full Date)
HTTP应用曾经一直允许三种不同日期/时间格式:
Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
第一种格式是作为Internet标准提出来的,它是一个国定长度的,由RFC 1123 [8](RFC 822[9]的升级版本)定义的一个子集。第二种格式使用比较普遍,但是基于废弃的RFC 850 [12],并且没有年份。如果HTTP/1.1客户端和服务器解析日期,他们必须能接收所有三种格式(为了兼容HTTP/1.0),但是它们只能产生RFC 1123里定义的日期格式来填充头域(header field)用到日期的地方。
注:日期值的接收者被鼓励能健壮的接收可能由非HTTP应用发来的日期值,例如有时可以通过代理(proxy)/网关(gateway)向SMTP或NNTP获得或转发消息。
所有的HTTP日期/时间都必须以格林威治时间(GMT)表示。对HTTP而言,GMT完全等同于UTC(世界协调时间)。前两种日期/时间格式里包含“GMT”,它是时区的三个字面的简写,并且当读到一个asctime格式时必须先被假定是GMT时间。HTTP日期(HTTP-date)区分大小写,不能包含一个额外的LWS,除非此LWS作为在下面的Http-date语法中指定的SP。
HTTP-date = rfc1123-date | rfc850-date | asctime-date
rfc1123-date = wkday "," SP date1 SP time SP "GMT"
rfc850-date = weekday "," SP date2 SP time SP "GMT"
asctime-date = wkday SP date3 SP time SP 4DIGIT
date1 = 2DIGIT SP month SP 4DIGIT
; day month year (e.g., 02 Jun 1982)
date2 = 2DIGIT "-" month "-" 2DIGIT
; day-month-year (e.g., 02-Jun-82)
date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
; month day (e.g., Jun 2)
time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
; 00:00:00 - 23:59:59
wkday = "Mon" | "Tue" | "Wed"
| "Thu" | "Fri" | "Sat" | "Sun"
weekday = "Monday" | "Tuesday" | "Wednesday"
| "Thursday" | "Friday" | "Saturday" | "Sunday"
month = "Jan" | "Feb" | "Mar" | "Apr"
| "May" | "Jun" | "Jul" | "Aug"
| "Sep" | "Oct" | "Nov" | "Dec"
注意:HTTP对日期/时间格式的要求仅仅应用在协议的消息(译注:原文是protocol stream,便于理解这里译作消息)里。客户和服务器不必把这种格式应用于用户呈现(user presentation),请求记录日志,等等。.
3.3.2 Delta Seconds
一些HTTP头域(header field)允许用整数秒表示时间值,整数秒用十进制表示,此整数秒表示消息被接收后时间。
delta-seconds = 1*DIGIT
3.4 字符集
HTTP使用术语"字符集"的定义,这和MIME中所描述的是一样.
本文档中的术语"字符集"涉及到一种方法,此方法是用一个或多个表将一个节序列转换成一个字符序列(译注:从这里来看,这应该是一种映射关系,表保存了映射关系)。注意反方向的无条件转换(译注:从一个字符序列到一个字节序列的转换)是不需要的,因为并不是所有的字符都能在一个给定的字符集里得到,一个字符集可能提供多个字节序列表征一个特定的字符。这个定义是为了允许不同种类的字符编码从单一简单表映射(如US-ASCII)到复杂表的转换方法如ISO-2022技术用到的。然而,与MIME字符集名字相关的定义必须要充分说明从字节到字符的映射。特别的,使用外部轮廓信息来精确确定映射是不允许的.
注:这里使用的术语"字符集"一般的被称作一种"字符编码"。不过既然HTTP和MIME在同一机构注册,术语统一是很重要的。
HTTP字符集是用不区分大小写的标记(token)表示。所有的标记集由IANA字符集注册机构[19]定义。
charset = token
尽管HTTP允许用任意标记(token)作为字符集(charset)值,但任何标记值如果它已经在IANA字符集注册机构注册了则必须表示在该注册机构定义的字符集。对那些非IANA定义的字符集,应用程序应该限制使用。
HTTP协议的实现者应该注意IETF字符集的要求[38][41].
3.4.1丢失的字符集(Missing Charset)
一些HTTP/1.0应用程序当他们解析Content-Type头时,当发现没有字符集参数(charset parameter,译注:Content-Type: text/plain; charset=UTF-8,此时charset=UTF-8就是字符集参数)可用时,这意味着接收者必须猜测实体主体(entity body,译注:这里翻译成“实体主体”因为Content-Type头是实体头,消息头可以分为实体头,常用头,请求头,响应头,在译文中多次用到“头”和“头域”,如消息头,消息头域,其实是同一个意思,HTTP1.1协议有时候概念并不是完全统一的)的字符集是什么。如果发送者希望避免这种情况,他应该在Content-Type头域里包含一个字符集参数,即使字符集是ISO-8859-1也应该这样做,这样就不会让接收者产生混淆。
不幸的是,一些旧的HTTP/1.0客户端不能处理在Content-Type头域里明确指定的字符集参数。HTTP/1.1接收端必须要认真对待发送者提供的字符集;并且当用户代理(user agent,译注:如浏览器,可认为是接收端)开始显示一个文档时,虽然用户代理可以猜测文档的字符集,但如果content-type头域里提供了字符集,并且用户代理也支持这种字符集的显示,不管用户代理是否愿意,它必须要利用这种字符集。参见3.7.1节。
3.5 内容编码(Content Codings)
内容编码值(content coding value)表示一种已经或可以应用于实体的编码转换(encoding transformation)。内容编码主要用于文档的压缩或其它有效的变换,但这种变换需要不能丢失文档的媒体类型(media type,译注:文档一般会有媒体类型,这通过在content-type里指定)的特性,也不能丢失文档的信息(译注:就像有损压缩和无损压缩,前者不会丢失信息,后者会丢失信息)。实体经常被编码的储存,然后直接传送,接收端只能解码。
content-coding = token
所有内容编码值(content-coding value)是不区分大小写的。HTTP/1.1在接收译码 (14.3节)和内容译码(Content-Encoding)(14.11节)头域里使用内容编码值(content-coding value)。尽管该值描述了内容编码,更重要的是它指出了一种解码机制,利用这种机制对实体的编码进行解码。
网络分配数字权威( (IANA)充当内容编码值标记(token)的注册机构。最初,注册表里包含下列标记:
gzip(压缩程序)
一种由文件压缩程序"gzip"(GNU zip)产生的编码格式(在RFC 1952中描述)。这种编码格式是一种具有32位CRC的Lempel-Ziv编码(LZ77)。
compress(压缩)
一种由UNIX文件压缩程序"compress"产生的编码格式。这种编码格式是一种具有可适应性的Lempel-Ziv-Welch编码(LZW)。
对于将来的编码,用程序名识表征编码格式是不可取。在这里用到他们是因为他们在历史的作用,虽然这样做并不好。为了同以前的HTTP实现相兼容,应用程序应该将"x-gzip"和"x-compress"分别等同于"gzip"和"compress"。
deflate(缩小)
deflate编码是由RFC 1950 [31]定义的"zlib"编码格式与RFC 1951 [29]里描述的"deflate"压缩机制的组合的产物。
identity(一致性)
Identity是缺省编码;指明这种编码表明不进行任何编码转换。这种内容编码仅被用于接收译码(Accept-Encoding)头域,但不能被用在内容译码(Content-Encoding)头域。.
新的内容编码值标记(token)应该被注册;为了实现客户和服务器间的互操作性,实现新值的内容编码算法规范应该能公开利用并且能独立实现,并且与本节中被定义的内容编码目的相一致。
3.6 传输编码 (Transfer Codings)
传输编码值(transfer-coding value,译注:transfer coding和和transfer-coding这两个术语在本协议规范里所表达的意思其实没什么太大区别,“transfer-coding”可能更能表达语意,因为它是规则中的规则名,见下面红字的规则)被用来表示一个已经,能够,或可能应用于一个实体的编码转换,传输编码是为了能够确保网络安全传输。这不同于内容编码(content coding),因为传输编码(transfer coding)是消息的属性而不是实体的属性。
transfer-coding = "chunked" | transfer-extension
transfer-extension = token *( ";" parameter )
参数(parameter)采用属性/值对的形式.
parameter = attribute "=" value
attribute = token
value = token | quoted-string
所有传输编码值(transfer-coding value,译注:上面红体字等号右边规则表达式所表达的值)是大小写不敏感。传输编码值在TE头域(14.39节)和在传输译码(Transfer-encoding) 头域中(14.41节)被运用。
无论何时,传输编码(transfer-coding)应用于一个消息主体(message body)时,如果存在多个传输编码,则这些传输编码中必须包括“块”("chunked")传输编码,除非通过关闭连接而中断消息。当“块”(“chunked”)传输编码被用于传输编码时,它必须是应用于消息主体的最后传输编码。"块"("chunked")传输编码最多只能用于消息主体(message-body)一次。规定了上述规则后,接收者就可以确定消息的传输长度(transfer-length)(4.4节)
传输编码与MIME[7]的内容传输译码(Content-Transfer-Encoding,译注:transfer应该是转移,迁移的意思,又例如HTTP协议,应该翻译成“超文本转移协议”,但是历史上都翻译成“超文本传输协议”,所以这里翻译成“超文本传输协议”)值有相类似型,它被定义能够实现在7位传输服务上保证二进制数据的传输安全。不过,传输编码与内容传输译码(Content-Transfer-Encoding)对纯8位传输协议有不同的关注点。在HTTP中,消息主体存在不安全的隐患,因为有时候很难确定消息主体的长度,在共享的传输上加密数据也会带来安全性问题(7.2.2节)。
网络分配数字权威(IANA)担任注册传输编码值标(token)记的角色。起初,注册包含如下标记:"块"(3.6.1节),"身份"(3.6.2节),"gzip"(3.5节),"压缩"(3.5节),和"缩小"(3.5节).
新的传输编码值标记应该注册,这同新的内容编码值标记也需要注册一样。.
接收端接收到一个带有传输编码(transfer-coding)(译注:通过消息头域transfer-encoding指明此实体主体的传输编码)的实体主体(entity body),如果它不能对这个编码后的实体主体进行解码,那么它应返回501(不能实现),并且要切断联系。服务器不能向HTTP/1.0客户发送传输编码.
3.6.1块传输编码(Chunked Transfer Coding)
块编码(chunked encoding)改变消息主体使消息主体(message body,译注:消息主体与实体主体是有区别的,后面章节将会介绍)成块发送。每一个块有它自己的大小(size)指示器,在所有的块之后会紧接着一个可选的包含实体头域的尾部(trailer)。这允许发送端能动态生成内容,并能携带有用的信息,这些信息能让接收者判断消息是否接收完整。
Chunked-Body(块正文) = *chunk(块)
last-chunk(最后块)
trailer(尾部)
CRLF
chunk(块) = chunk-size [ chunk-extension ] CRLF
chunk-data CRLF
chunk-size = 1*HEX
last-chunk = 1*("0") [ chunk-extension ] CRLF
chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)
trailer = *(entity-header CRLF)
chunk-size是用16 进制数字字符串。块编码(chunked encoding)以任一大小为0的块结束,紧接着是尾部(trailer),尾部以一个空行终止。
尾部(trailer)允许发送端在消息的末尾包含附加的HTTP头域(header field)。Trailer头域(Trailer header field,译注:Trailer头是常用消息头,在14.40节说明)被应用来指明哪些头域被包含在块编码的尾部(trailer) (见14.40节)
如果服务器要用块传输编码进行响应,它不能包含尾部(trailer),除非以下至少一条为真:
a)如果此响应的请求包括一个TE头域,并且它指明了传输编码中的“trailers”是可接受的,当响应的传输编码(transfer-coding)是块编码时。这在14.39节中描述;或者
b)如果服务器是响应的源服务器,并且接收端接收块传输编码响应但不会去理会响应的尾部(trailer,译注:尾部包含头域,头域就是消息的元数据(metadata))并且这种方式源服务器是可以接受的,这时服务器是不需要把尾部(trailer)包含进消息的块传输编码中去的。换句话说,源服务器原意接受尾部(trailer)可能会在到达客户端时被丢弃的可能性。
此要求防止了一种互操作性的失败,当消息被一个HTTP/1.1(或更迟的)代理(proxy)接收并且转到一个HTTP/1.0的接收端的时候。
在附录19.4.6节介绍了一个例子,这个例子介绍怎样对一个块正文(chunked-body)进行解码。
所有HTTP/1.1应用程序必须能接收和解码块(chunked)传输译码,并且必须忽略它们不能理解的块扩展(chunk-extentsion,译注:见上面的规则表达式).
3.7 媒体类型(Media Type)
HTTP在Content-Type(14.17节)实体头域和Accept请求头域里利用网络媒体[17]类型,这是为了提供公开的,可扩展的数据打印和类型协商。
media-type = type "/" subtype *( ";" parameter )
type = token
subtype = token
参数(parameter)以一种属性/值对的形式跟随type/subtype(如3.6节定义) 。
类型(type),子类型(subtype),和参数(parameter)里属性名称是大小写不敏感的。参数值有可能是大小写敏感的,也可能不是,这根据参数里属性名的语意。线性空白(LWS)不能被用于类型(type)和子类型(subtype)之间,也不能用于参数的属性和值之间。参数的出现或不出现对处理媒体类型(media-type)可能会有帮助,这取决于它在媒体类型注册表里的定义。
注意一些旧的HTTP应用程序不能识别媒体类型的参数(parameter)。当向一个旧的HTTP应用程序发送数据时,发送端只有在被type/subtype定义需要时才使用类型参数(parameter)。
媒体类型(media-type)值需要被注册到网络数字分配权威(IANA[19])里。媒体类型的注册程序在RFC 1590[17]中大概描述。使用未经注册的媒体类型是不被鼓励的。
3.7.1规范化和文本缺省 (Canonicalization and Text Defaults)
网络媒体类型以规范化的格式被注册。一个实体主体(entity-body)通过HTTP消息传输,它必须在传输前以一种合适的规范化的格式表征除了文本类型(text type),文本类型将会在下一段阐述。
当消息以一种规范化的格式表现时,文本类型的子类型(subtype)运用GRLF作为文本里的换行符。HTTP放松了这个要求,并且允许文本媒体以一个CR或LF代表一个换行符传输,并且这样做要贯穿整个实体主体(entity-body)。HTTP应用程序必须能接收CRLF,CR和LF作为在文本媒体一个换行符。另外,如果文本字符集(character set)不能用字节13和10来分别地表征CR和LF因为存在一些多字节字符,HTTP允许应用字符集里等价于CR和LF的字节序列来表示换行符。对换行符的灵活处理只能应用于实体主体里的文本媒体;在HTTP消息结构里,一个单独的CR或LF都不能代替CRLF(如头域和多边界体(multipart boundaries)结构里)。
如果一个实体主体(entity-body)用内容编码(content-coding)进行编码,原始数据(译注:被编码前的数据)在被编码前必须是一种定义的媒体类型格式。.
"charset"参数(parameter)被应用于一些媒体类型,来定义数据的字符集(见3.4节)。当发送者没有在媒体类型(media-type)里指明charset参数(parameter)时,文本类型的子媒体类型(subtype)被认为是缺省的ISO-8859-1字符集当被接收者接收后。数据必须被合适的字符集标识。3.4.1节描述了兼容性问题。
3.7.2多部分类型(Multipart type)
MIME提供了一系列"多部分"类型---在单个消息主体内包装一个或多个实体。所有的多部分类型共享一个公共的语法(这在RFC 2046[40]的5.1.1节中描述),并且包含一个边界(boundary)参数作为多部分媒体类型值的一部分。多部分类型的消息主体是一个协议元素,并且必须用CRLF来标识体部分(body-part,译注:见RFC 2046 的5节)之间的换行。
不同于RFC 2046里的多部分消息类型的描述,HTTP1.1规定任何多部分类型的消息尾声(epilogue,译:见RFC 2046对多部分消息类型的规则描述)必须不能存在;HTTP应用程序不能传输尾声(epilogue)(即使原始的多部分消息尾部包含一个尾声)。存在这些限制是为了保护多部分消息主体的自我定界的特性,因为多部分边界的结束(译注:根据RFC2046中定义,多部分边界结束后可能还会有尾声)标志着消息主体的结束。
通常,HTTP把一个多部分类型的消息主体(message-body)和任何其他媒体类型的消息主体相同对待:严格看作有用的负载体。有一个例外就是"multipart/byterange"类型(附录19.2),当它出现在206(部分内容)响应时,此响应会被一些HTTP缓存机制解析,缓存机制将会在13.5.4节和14.16节介绍。在其它情况下,一个HTTP用户代理会遵循MIME用户代理一样的或者相似的行为,这依赖于接收何种多部分类型。一个多部分类型消息的每一个体部分(bady-part)里的MIME头域对于HTTP并没有太大意义除了MIME语意。
通常, 一个HTTP用户代理应该遵循与一个MINE用户代理相同或相似。如果一个应用程序收到一个不能识别的多部分子类型,这个应用程序必须将它视为"multipart/mixed"。
注:"multipart/form-data"类型已经被规范的定义为传送窗体数据(译注:一般用窗体上传数据时,上传的数据类型就是为multipart/form-data类型),当用POST请求方法处理数据时。这在RFC 1867[15]里定义。
3.8 产品标记 (product Tokens)
产品标记用产品名和版本号识别通讯应用软件。很多头域都会利用产品标记,它允许构成应用程序重要部分的子产品被以空白分隔列举。通常,产品以应用程序的重要性的顺序来列举的。
product = token ["/" product-version]
product-version = token
例:
User-Agent:CERN-LineMode/2.15 libwww/2.17b3
Server: Apache/0.8.4
产品标示应言简意赅。它们不能用来做广告或其他不重要的信息。虽然任一标记可能出现product-version里,但这个标记仅能用来做一个版本 (i.e., 同产品中的后续版本应该在product-version上有区别)
3.9 质量值(Quality Values)
HTTP内容协商(content negotiation,12节介绍)运用短“浮点”数字(short floating point number)来表针不同协商参数的相对重要性。重要性的权值被规范化成一个从0到1的实数。0是最小值,1是最大值。如果一个参数的质量值(quanlity value)为0,那么这个参数的内容不被客户端接受。HTTP/1.1应用程序不能产生多于三位小数的实数。下面规则限定了这些值。
qvalue = ( "0" [ "." 0*3DIGIT ] )
| ( "1" [ "." 0*3("0") ] )
"质量值" 是一个不当的用词,因为这些值仅仅表现一中相对的降级。
3.10 语言标签 (Language Tags)
一个语言标签表征一种自然语言,这种自然语言能说,能写,或者被用来人与人之间的沟通。计算机语言明显不包括在内的。HTTP在Accept-Language和Content-Language头域里应用到语言标签(language tag)。
HTTP语言标签的语法和注册和RFC 1766[1]中定义的一样。总之,一个语言标签是由一部分或多部分构成:一个主语言标签和可能为空的子标签系列。
Language-tag = primary-tag*("-" subtag)
primary = 1*8ALPHA
subtag = 1*8ALPHA
标签中不允许出现空格,标签大小写不敏感(case-insensitive)。由IANA来管理语言标签中的名字。典型的标签包括:
en, en-US, en-cockney, i-cherokee, x-pig-latin
上面的任意两个字母的主标签是一个ISO-639语言的缩,并且两个大写字母的子标签是一个ISO-3166的国家代码。(上面的最后三个标签是未经注册的标签;但是除最后一个之外所有的标签都会将来注册)。
3.11 实体标签 (Entity Tags)
实体标签被用于比较相同请求资源中两个或更多实体。HTTP/1.1在ETag(14.19节),If-match(14.24节),If-None-match(14.26节)和If-Rang(14.27节)头域中运用实体标签。关于它们怎样被当作一个缓存验证器(cache validator)而使用和比较在13.3.3节被定义。一个实体标签由一个给定的晦涩的引用字符串(opaque quoted string),还可能前面带一个弱指示器组成。
entity-tag = [ weak ] opaque-tag
weak = "W/"
opaque-tag = quoted-string
一个“强实体标签”如果被一个资源的两个实体里共享,那么这两个实体必须在字节上等价。
一个“弱实体标签”是以"W/"前缀的,它可能会被一个资源的两个实体共享,如果这两个实体是等价的,并且能彼此之间能互相替代,并且也不会在语义上有太大改变。一个弱实体标签只能用于弱比较(weak comparison)。
在一个特定资源的所有实体版本里,一个实体标签必须能唯一。一个给定的实体标签值可以被于不同的URI请求用来获得的实体。相同实体标签值运用于不同URI请求获得的实体,并不意味着这些实体是等价的。
3.12 范围单位(Range Units)
HTTP/1.1允许一个客户请求响应实体的一部分。HTTP/1.1在Range(14.35节)和Content-Range(14.16节)头域里应用范围单位(range units)。任何实体根据不同的结构化单元都能被分解是子范围
range-unit = bytes-unit | other-range-unit
bytes-unit = "bytes"
other-range-unit = token
HTTP/1.1中定义的唯一的范围单位是"bytes"。HTTP/1.1实现时可能忽略其他单位指定的范围。
HTTP/1.1被设计允许应用程序实现不依靠有关对范围的了解。
4 HTTP消息
4.1 消息类型(Message Types)
HTTP消息由从客户到服务器的请求和从服务器到客户的响应组成.
HTTP-message = Request|Response ;HTTP/1.1
请求(第5节)和响应(第6节)消息利用RFC 822[9]定义的常用消息的格式,这种消息格式是用于传输实体(消息的负载)。两种类型的消息由开始行(start-line),零个或更多个头域(经常被称作“头”),一个指示头域结束的空行(也就是,一个以CRLF为前缀的什么也没有的行),一个可有可无的消息主体(message-body)。
generic-message = start-line
*(message-header CRLF)
CRLF
[ message-body ]
start-line = Request-Line | Status-Line
为了健壮性,服务器应该忽略任意请求行(Request-Line)前面的空行。换句话说,如果服务器开始读消息流的时候发现了一个CRLF,它应该忽略这个CRLF。
一般一个有问题的HTTP/1.0客户端会在POST请求消息之后产生额外的CRLF。为了重述什么是BNF明确禁止的,一个HTTP/1.1客户端不能在请求前和请求后加一些不必要的CRLF。
4.2 消息头 (Message Headers)
HTTP头域包括常用头(4.5节),请求头(5.3节),响应头(6.2节)和实体头(7.1节)域。它们遵循RFC822[0]3.1节中给出的同一个常规的格式。每一个头域由一个名字(域名)跟随一个":"和域值构成。域名是大小写不敏感的。域值前面可能有任意数量的LWS的。但SP(空格)是首选的。头域能被延升多行,通过在这些行前面加一些SP或HT。应用程本应该遵循“常用格式”当产生HTTP消息时,因为可能存在一些应用程序,他们不能接收任何常用形式之外的形式。.
message-header = field-name ":" [ field-value ]
field-name = token
field-value = *( field-content | LWS )
field-content =
and consisting of either *TEXT or combinations
of token, separators, and quoted-string>
filed-content不包括任何前导或后续的LWS(线性空白):线性空白出现在域值(filed-value)的第一个非空白字符之前或最后一个非空白字符之后。前导或后续LWS可能会被移除而不会改变域值的语意。任何出现在filed-content之间的LWS可能会被一个SP代替在解析域值之前或把这个消息往下流传递时。.
不同域名的头域被接收的顺序是不重要的。然而,首先发送常用头域,然后紧接着是请求头域或者是响应头域,然后是以实体头域结束,这样做是一个好的的方法。
多个消息头域使用同一个域名(filed-name)可能会出现在一些消息中,如果一个头域的域值被定义成一个以逗号隔开的列表。把相同名的多个头域结合成一个“域名:域值”对的形式而不改变消息的语意,可以通过把每一个后续的域值加到第一个里,每一个域值用逗号隔开。同名的头域的接收顺序对合并的域值的解释有重要意义,所以代理(proxy)不能改变域值的顺序,当它把此消息再次转发时。
4.3 消息主体 (Message Body)
HTTP消息的消息主体用来承载请求和响应的实体主体(entity-body)。这些消息主体(message-body)仅仅当传输编码(transfer-coding)应用于传输译码(Transfer-Encoding)头域时才和实体主体(entity-body)不同,其它情况消息主体和实体主体相同。传输译码头域在14.41节阐述。
message-body=entity-body|
传输译码头域被用来指明应用程序的传输编码,它是为了保证安全和适合的消息传输。传输译码(Transfer-Encoding)头域是消息的属性,而不是实体的属性,并且沿着请求/响应链能被添加或删除。(然而,3.6节描述了一些限制当使用某个传输编码时)
什么时候消息主体(message-body)允许出现在消息中,这根据不同请求和响应来决定的。
请求中消息主体(message-body)的存在是被请求中消息头域中是否存在内容长度(Content-Length)或传输译码(Transfer-Encoding)头域来暗示的。一个消息主体(message-body)不能被包含在请求里如果请求方法(见5.1.1节)不允许请求里包含实体主体(entity-body)。一个服务器应该能阅读或再次转发请求里的消息主体;如果请求方法不允许包含一个实体主体(entity-body),那么消息主体应该被忽略当服务器处理这个请求时。
对于响应消息,消息里是否包含消息主体依赖相应的请求方法和响应状态码。所有HEAD请求方法的请求的响应消息不能包含消息主体,即使实体头域出现在请求里。所有1XX(信息的),204(无内容的)和304(没有修改的)的响应都不能包括一个消息主体(message-body)。所有其他的响应必须包括消息主体,虽然它可能长度为零.
4.4 消息的长度(Message Length)
一条消息的传输长度(transfer-length)是消息主体(message-body)的长度,当消息主体出现在消息中时;那就是说在实体主体被应用了传输编码(transfer-coding)后。当消息中出现消息主体时,消息主体的传输长度(transfer-length)由下面(以优先权的顺序)决定::
1。任何不能包含消息主体(message-body)的消息(这种消息如1xx,204和304响应和任何HEAD请求的响应)总是被头域后的第一个空行(译注:CRLF)终止,不管消息里是否有实体头域(entity-header fields)。
2。如果Transfer-Encoding头域(见14.41节)出现,并且它的域值不是”identity”,那么传输长度(transfer-length)被“块”传输编码定义,除非消息因为关闭连接而被终结了。
3。如果Content-Length头域(属于实体头域)(见14.13节)出现,那么它的十进制值(以字节表示)就代表实体主体长度(entity-length,译注:实体长度其实就是实体主体的长度,以后把entity-length翻译成实体主体的长度)也代表传输长度(transfer-length)。Content-Length头域不能包含在消息中,如果实体主体长度(entity-length)和传输长度(transfer-length)两者不相等(也就是说,消息里应用了传输译码(Transfer-Encoding)头域)。如果一个消息即有传输译码(Transfer-Encoding)头域并且也Content-Length头域,后者会被忽略。
4。如果消息用到媒体类型“multipart/byteranges”,并且传输长度(transfer-length)另外也没有指定,那么这种自我定界的媒体类型定义了传输长度(transfer-length)。这种媒体类型不能被利用除非发送者知道接收者能怎样去解析它; HTTP1.1客户端请求里如果出现Range头域并且带有多个字节范围(byte-range)指示符,这就意味着客户端能解析multipart/byteranges响应。
一个Range请求头域可能会被一个不能理解multipart/byteranges的HTTP1.0代理(proxy)再次转发;在这种情况下,服务器必须能定界此消息利用这节的1,3或5项里定义的方法。
5。通过服务器关闭连接能确定消息的传输长度。(关闭连接并不能用来指明请求消息体的结束,因为这样可以让服务器没有机会继续给予响应)。
为了与HTTP/1.0应用程序兼容,包含HTTP/1.1消息主体的请求必须包括一个有效的内容长度(Content-Length)的头域,除非服务器是和HTTP/1.1遵循的。如果一个请求包含一个消息主体并且没有给出内容长度(Content-Length),那么服务器应该以400响应(错误的请求)如果他不能判断消息长度的话,或者以411响应(要求长度)如果它坚持想要收到一个有效内容长度(Content-length)。
所有的能接收实体的HTTP/1.1应用程序必须能接受"chunked"的传输编码(3.6节),因此可以允许这种机制来处理消息当消息的长度不能被提前决定时。
消息不能同时都包括内容长度(Content-Length)头域和非identity传输编码。如果消息包括了一个非identity的传输编码,内容长度(Content-Length)头域必须被忽略.
当内容长度(Content-Length)头域出现一个具有消息主体(message-body)的消息里,它的域值必须精确匹配消息主体里字节数量。HTTP/1.1用户代理必须通知用户当一个无效的长度接收了。
4.5 常用头域(General Header Fields)
有一些头域即适用于请求也适用于响应消息,但是这些头域并不适合被传输的实体。这些头域只能应用与被传输的消息。
general-header = Cache-Control ; Section 14.9
| Connection ; Section 14.10
| Date ; Section 14.18
| Pragma ; Section 14.32
| Trailer ; Section 14.40
| Transfer-Encoding ; Section 14.41
| Upgrade ; Section 14.42
| Via ; Section 14.45
| Warning ; Section 14.46
常用头域的名能被扩展,但这要和协议版本的变化相结合。然而,新的或实验性的头域可能被赋予常用头域的语意,如果通信里的所有参与者都认为他们是常用头域。不被识别的头域会被作为实体头(entity-header)头域来看待。
5 请求(Request)
一个请求消息是从客户端到服务器端的,在消息首行里包含方法,资源指示符,协议版本。
Request = Request-Line ; Section 5.1
*(( general-header ; Section 4.5
| request-header ; Section 5.3
| entity-header ) CRLF) ; Section 7.1
CRLF
[ message-body ] ; Section 4.3
5.1 请求行 (Request-Line)
请求行(Request-Line)是以一个方法标记开始,后面跟随Request-URI和协议版本,最后以CRLF结束。元素是以SP字符分隔。CR或LF是不被允许的除了最后的CRLF。
Request-Line =Method SP Request-URL SP HTTP-Version CRLF
5.1.1方法 (Method)
方法标记指示了在被Request-URI指定的资源上执行的方法。这种方法是大小写敏感的。
Method = "OPTIONS" ;9.2节
| "GET" ;9.3节
| "HEAD" ;9.4节
|"POST" ;9.5节
|"PUT" ;9.6节
|"DELETE" ;9.7节
|"TRACE" ;9.8节
|"CONNECT" ;9.9节
| extension-method
Extension-method = token
资源允许的方法由Allow头域指定(14.7节)。响应的返回码总是通知客户是否一个方法对一个资源在当前是被允许的,因为被允许的方法集合能被动态的改变。一个源服务器应该返回405状态码(方法不能允许)如果此方法对于一个请求资源在服务器那里不被允许,并且返回501状态码(没有实现)如果此方法不被源服务器识别或实现。方法GET和HEAD必须被所有常规目的的服务器支持。所有其它的方法是可选的;然而,如果上面的所有方法都被实现,这些方法必须遵循的语意和第9节指定的相同。
5.1.2请求URL(Request-URI)
Request-URI是一种全球统一资源标识符(3.2 节),并且它指定请求的资源。
Request-URI ="*" | absoluteURI | abs_path | authotity
Request-URI的OPTIONS依赖于请求的性质。星号"*"意味着请求不能应用于一个特定的资源,但是能应用于服务器,并且只能被允许当使用的方法不能应用于资源的时候。举例如下
OPTIONS * HTTP/1.1
当向代理(proxy)提交请求时,绝对URI(absoluteRUI)是不可缺少的。代理(proxy)可能会被要求再次转寄此请求。注意:代理可能再次提交此请求到另一个代理或直接给源服务器。为了避免循环请求,代理(proxy)必须能识别所有的服务器名字,包括任何别名,本地变量,数字IP地址。一个请求行(Request-Line)的例子如下:
GET http://www.w3.org/pub/www/TheProject.html HTTP/1.1
为了未来HTTP版本的所有请求能迁移到绝对URI(absoluteURI)地址,所有基于HTTP/1.1的服务器必须接受绝对URL地址,即使HTTP/1.1的客户端只向代理产生给绝对URI(absoluteU