本文档规定了互联网社区的标准组协议,并需要讨论和建议以便更加完善。请参考
“互联网官方协议标准”(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应用程序的激增,这就迫切需要一个新的版本,以便能使两个通信程序能够确定彼此的真实能力。
此规范定义的协议叫做“HTTP/1.1”,.这个协议与HTTP/1.0相比,此规范更为严格,以确保各个协议的特征得到可靠实现。
实际的信息系统除了简单的获取信息之外,还要求更多的功能,包括查找(search),终端更新(front-end update)和注解(annotation)。HTTP为请求提供可扩充方法集和消息头集[47]。HTTP是建立在统一资源标识符(URI)[3]的约束上的,作为一个地址(URL)[4]或名称(URN)[20],以指定被一个方法使用的资源。消息以一种类似于互联网邮件[9]消息格式来传输的,互联网消息格式定义于多目的互联网邮件扩展(MIME)[7]里。
HTTP也是用于用户代理(user agents)和其它互联网系统的代理/网关之间通信的通信协议,这些互联网系统可能由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)保存其副本,为的是能响应后续请求。确定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协议是一种请求/响应型的协议。 客户端给服务器发送请求的格式是一个请求方法(request method),URI,协议版本号,然后紧接着一个包含请求修饰符(modifiers),客户端信息,和可能的消息主体的类MIME(MIME-like)消息。服务器对请求端发送响应的格式是以一个状态行(status line),其后跟随一个包含服务器信息、实体元信息和可能的实体主体内容的类MIME(MIME-like)的消息。其中状态行(status line)包含消息的协议版本号和一个成功或错误码。HTTP和MIME之间的关系如附录19.4节所阐述。
大部分的HTTP通信是由用户代理(user agent)发起的,由应用于一个源服务器资源的请求构成。最简单的情形,这可以通过用户代理(UA)和源服务器(O)之间的单一连接(v)来实现。
请求链(Request chain)-------------------------------------- ----------à
用户代理(UA)----------------单一连接(v)--------------源服务器(O)
<----------------------------------------------------------响应链(response chain)
有可能在请求/响应链中出现一个或多个中间者(intermediares),这是比较复杂的情形。常见的中间者(intermediares)有三种:代理(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的服务器,与此同时C正在处理A的请求。
通信中任何非隧道成员都可能会采用一个内部缓存(internal cache)来处理请求。如果沿着链的成员有请求已缓存的响应,请求/响应链就会大大缩短。下图阐明了一个最终请求响应链,假定B拥有一个来自于O(通过C)的以前请求响应的缓存副本,并且此请求的响应并未被UA或A缓存。
请求链(request chain)---------->
UA-----v----------A-----v-----B-----C----O
<---------响应链 (response chain)
并不是所有的响应都能有效地缓存,一些请求可能含有修饰符(modifiers),这些修饰符对缓存动作有特殊的要求。HTTP对缓存行为(behavior)和可缓存响应(cacheable responses)的定义在第13章定义。
实际上,目前万维网上有多种被实践和部署的缓存和代理的体系结构和配置。这些系统包括节省带宽的缓存代理(proxy cache)层次(hierarchies)系统,可以广播(broadcast)或多播(multicast)缓存数据的系统,通过CD-ROM发布缓存数据子集的机构,等等。HTTP系统(http system)会被应用于宽带连接的企业局域网中的协作,并且可以被用于PDAs进行低耗无线断续连接访问。HTTP1.1的宗旨是为了支持各种各样的已经部署的配置,同时引进一种协议结构,让它满足可以建立高可靠性的web应用程序,即使不能达到这种要求,也至少可以可靠的定位故障。
HTTP通信通常发生在TCP/IP连接上。默认端口是TCP 80,不过其它端口也可以使用。但并不排除HTTP协议会在其它协议之上被实现。HTTP仅仅期望的是一个可靠的传输(译注:HTTP一般建立在传输层协议之上);所以任何提供这种保证的协议都可以被使用;协议传输数据单元(transport data unit)与HTTP/1.1请求和响应的消息结构之间的映象已经超出了本规范的范围。
大部分HTTP/1.0的实现都是对每个请求/响应交换(exchange)产生一个新的连接。而HTTP/1.1中,一个连接可以用于一个或更多请求/响应交换,虽然连接可能会因为各种原因中断(见第8.1节)。
2 符号习惯和一般语法
2.1 扩充的BNF(扩充的 巴科斯-诺尔范式)
本文档规定的所有机制都用两种方法描述:散文体(prose)和类似于RFC 822的扩充Backus-Naur Form(BNF)。要理解本规范,使用者需熟悉符号表示法。扩充BNF结构如下:
名字(name)=定义(definition)
名字(name)就是代表规则的名字,规则名里不能包含“<”和“>”,通过等号把规则名和规则定义(definiation)分离开。空格只有在采用延续行缩进来指定跨度多于一行的规则定义的时候才有意义。某些基本规则(basic rules)使用大写字母包含在规则定义里, 如SP,LWS,HT,CRLF,DIGIT,ALPHA,等等。尖括号可以包含在规则定义里,只要它们的存在有利于区分规则名的使用。
“字面文本”(“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”。
*规则
前面的字符“*”表示重复。完整的形式是“<n>*<m>元素”,表示元素至少出现<n>次,至多出现<m>次。默认值是0和无穷大,所以"*(元素)"允许任何数值,包括零;"1*元素"至少出现一次;"1*2element"允许出现一次或两次。
[规则]
方括号里是任选元素;“[foo bar]”相当于“*1(foo bar)”。
N 规则
特殊的重复:“<n>(元素)”与“<n>*<n>(元素)”等价;就是说,(元素)正好出现<n>次。这样2DIGIT是一个两位数字,3ALPHA是一个由三个字符组成的字符串。
#规则
类似于“*”,结构“#”是用来定义一系列元素的。完整的形式是<n>#<m>元素,表示至少<n>个元素,至多<m>个元素,元素之间被一个或多个逗号(“,”)以及可选的线性空白(LWS)隔开了。这就使得表示列表这样的形式变得非常容易;像
(*LWS element *(*LWS ","*LWS element))
就可以表示为
1#element
无论在哪里使用这个结构,空元素都是允许的,但是不计入元素出现的次数。换句话说 ,
“(element ), , (element) ”是允许的,但是仅仅视为两个元素。因此,在至少需要一个元素的地方,必须存在至少一个非空元素。默认值是0和无穷大,这样,“#element”允许任意零个或多个元素;“1# element”需要至少一个;“1#2element”允许一个或两个元素。
注释(comment)
用分号引导注释。
隐含的*LWS
本规范所描述的语法是基于字(word-based)的。除非特别注明,线性空白(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 = <US-ASCII CR, 回车(13)>
LF = <US-ASCII LF, 换行符(10)>
SP = <US-ASCII SP, 空格(32)>
HT = <US-ASCII HT, 水平制表 (9)>
<"> = <US-ASCII双引号(34)>
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”的域里。在其他域里,圆括号被视作域值的一部分。
comment (注释)= "(" *(ctext | quoted-pair | comment )” )"
ctext = <除"(" 和 ")"以外的任意TEXT >
如果一个TEXT若被包含在双引号里,则当作一个字。
quoted-string = ( <"> *(qdtext | quoted-pair ) <"> )
qdtext = <any TEXT except <">>
斜划线(""")可以被作为单字符的引用机制,但是必须要在quoted-string和comment构造之内。
quoted-pair = """ CHAR
3 协议参数
3.1 HTTP版本
HTTP使用一个“<major>.<minor>”数字模式来指明协议的版本号。为了进一步的理解HTTP通信,协议的版本号指示了发送端指明消息的格式和能力,而不仅仅是通过双方通信而获得的通信特性。当消息元素的增加不会影响通信行为或扩展了域值时,协议版本是不需要修改的。当协议会因为添加一些特征而做了修改时,<minor>数字就会递增。这些修改不会影响通常的消息解析算法,但它会给消息添加额外的语意(semantic)并且会暗示发送者具有额外的能力。协议的消息格式发生变化时,<major>数字就会增加。
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-Version里,并且对任何不兼容HTTP/1.0的消息也必须这么做。关于何时发送特定的HTTP-Version值的细节,参见RFC2145[36]。
应用程序的HTTP版本是应用程序最少条件遵循的最高HTTP版本。
当代理或网关应用程序转发(forwarding)消息的协议版本不同于代理或网关应用程序本身协议版本的时候,代理(proxy)和网关(gateway)应用程序就要小心。因为消息里协议版本说明了发送者处理协议的能力,所以一个代理/网关千万不要发送一个高于该代理/网关应用程序协议版本的消息。如果代理或网关接收了一个更高版本的消息,它必须要么使协议的版本降低,要么以一个错误响应,或者要么切换到隧道行为(tunnel behavior)。
自从RFC 2068[33]发布后,由于存在与HTTP/1.0代理(proxy)的互操作问题,所以缓存代理(caching proxies)必须能提升请求的版本到他们能支持的程度,但网关(gateway)可以这么做也可以不这么做,而隧道(tunnels)却不能这么做。代理(Proxy)/网关(gateway)的响应(Response)必须和请求(request)的主版本(major version)号保持一致。
注意:HTTP版本间的转换可能会对消息头域(header fields)在版本里有或没有而进行改变。
3.2 通用资源标识符(URI)
URIs有许多名字已为人所知:WWW地址,通用文档标识符,通用资源标识符[3],以及后来的统一资源定位器(URL)[4]和统一资源名称(URN)[20]。就HTTP而言,通用资源标识符(URI)只是简单的格式化字符串---通过名称,位置,或其它特征---识别一个资源。
3.2.1一般语法
根据使用的背景,HTTP里的URIs可以表示成绝对(absoulute)形式或相对形式(相对URI基于根URI[11])。两种形式的区别是根据这样的事实:绝对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,并且应该能够处理无限长度的URIs,这种无效长度的URL可能会在客户端以基于GET方式的请求时产生。如果服务器不能处理太长的URI的时候,服务器应该返回414状态码(此状态码代表Request-URI太长)。
注:服务器在依赖大于255字节的URI时应谨慎,因为一些旧的客户或代理实现可能不支持这些长度。
3.2.2 HTTP URL
在HTTP协议里,http模式(http scheme)被用于定位网络资源(resourse)的位置。本节定义了http URLs这种特定模式(scheme)的语法和语义。
http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]
如果端口为空或未给出,就假定为80。它的语义即:已识别的资源存放于正在监听tcp连接的那个端口的服务器上,并且请求资源的的Request-UR为绝对路径(5.1.2节)。无论什么可能的时候,URL里使用IP地址都是应该避免的(参看RFC 1900 [24])。如果绝对地址(abs_path)没有出现在URL里,那么应该给出"/"。如果代理(proxy)收到一个主机(host)名,但是这个主机名不是全称域名(fully quanlified domain name),则代理应该把它的域名加到主机名上。如果代理(proxy)接收了一个全称域名,代理不能改变主机(host)名称。
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-date的地方。
注:日期值的接收者被鼓励能可靠地接收来自于非HTTP应用程序发送的的日期值,例如有时可以通过代理(proxy)/网关(gateway)向SMTP或NNTP获取或提交消息。
所有的HTTP日期/时间都必须以格林威治时间(GMT)表示。对HTTP而言,GMT完全等同于UTC(世界协调时间)。前两种日期/时间格式里包含“GMT”,它是时区的三个字面的简写,并且当读到一个asctime格式时必须先被假定是GMT时间。HTTP日期(HTTP-date)区分大小写,不能在此语法中除SP之外包含一个多余的LWS。
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对日期/时间格式的要求仅仅应用在协议流的使用。客户和服务器不必把这种格式应用于用户呈现(user presentation),请求记录日志,等等。.
3.3.2 Delta Seconds(秒间隔)
一些HTTP头域(header field)允许时间值以秒为单位,以十进制整数表示,此值代表消息接收后的时间。
delta-seconds = 1*DIGIT
3.4 字符集 (Character Sets)
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头域里包含一个字符集参数,即使字符集是ISO-8859-1的也应该指明,这样就不会让接收者产生混淆。
不幸的是,一些旧的HTTP/1.0客户端不能处理在Content-Type头域里明确指定的字符集参数。HTTP/1.1接收端必须要认真对待发送者提供的字符集;并且当用户代理(user agent,译注:如浏览器)开始呈现一个文档时,虽然用户代理可以猜测文档的字符集,但如果content-type头域里提供了字符集,并且用户代理也支持这种字符集的显示,不管用户代理是否愿意,它必须要利用这种字符集。参见3.7.1节。
3.5 内容编码(Content Codings)
内容编码(content coding)的值表示一种曾经或能被应用于一个实体的编码转换(encoding transformation)。内容编码主要用于文档的压缩或其它有效的变换,但这种变换必须不能丢失文档的媒体类型的特性,并且不能丢失文档的信息(译注:就像有损压缩和无损压缩,前者不会丢失信息,后者会丢失信息)。实体经常被编码后保存,然后传送出去,并且在接收端被解码。
content-coding = token
所有内容编码(content-coding)的值是不区分大小写的。HTTP/1.1在接受译码 (Accept-Encoding,14.3节)和内容译码(Content-Encoding)(14.11节)头域里使用内容编码(content-coding)的值。尽管该值描述了内容编码,更重要的是它指出了一种解码机制,利用这种机制对实体的编码进行解码。
网络分配数字权威( (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 ,译注: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
所有传输编码的值是大小写不敏感。传输编码的值在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,MIME [7])的值相似,它被定义能够实现在7位传输服务上保证二进制数据的安全传输。不过,传输编码与内容传输译码(Content-Transfer-Encoding)对纯8位传输协议有不同的侧重点。在HTTP中,消息主体存在不安全的特性是因为有时候很难确定消息主体的长度(7.2.2节)和在共享的传输上加密数据。
网络分配数字权威(IANA)担任注册传输编码的值标记(token)的角色。起初,注册包含如下标记:"块"(3.6.1节),"身份"(3.6.2节),"gzip"(3.5节),"压缩"(3.5节),和"缩小"(3.5节).
新的传输编码的值标记应该注册,这同新的内容编码的值标记也需要注册一样。.
如果接收端接收到一个经过传输编码编码过的实体主体(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,在14.40节阐述)来指明哪些头域被包含在块传输编码的尾部(trailer) (见14.40节)
如果服务器要使用块传输编码进行响应,除非以下至少一条为真时它才能包含尾部(trailer):
a)如果此响应的对应请求包括一个TE头域,并且利用 “trailers”指明了块传输编码响应的尾部是可以接受的(TE头域在14.39节中描述;或者
b)如果是源服务器进行响应,响应里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)以一种 属性/值(attribute/value)形式(如3.6节定义)跟随 类型/子类型(type/subtype)。
类型(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消息控制结构(如头域和多边界体(multipart boundaries))里,一个纯粹的CR或LF都不能代替CRLF的作用。
如果一个实体主体(entity-body)用内容编码(content-coding)进行编码,原始数据在被编码前必须是一种以上定义的媒体类型格式。.
"charset"参数(parameter)被应用于一些媒体类型,来定义数据的字符集(见3.4节)。当发送端没有指明charset参数(parameter)时,“text”类型的子媒体类型(subtype)被接收端接收后会被认为是缺省的ISO-8859-1字符集。非“ISO-8859-1”字符集和它的子类(subsets)的数据必须被指示恰当的字符集。3.4.1节描述了兼容性问题。
3.7.2多部分类型(Multipart type)
MIME提供了一系列“多部分”(multipart)类型---在单个消息主体内包装一个或多个实体。所有的多部分类型共享一个公共的语法(这在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用户代理一样或者相似的行为,这依赖于接收何种多部分类型。一个多部分类型消息的每一个体部分(body-part)里的MIME头域对于HTTP除了MIME语意并没有太大意义。
通常, 一个HTTP用户代理应该遵循与一个MIME用户代理相同或相似的行为。如果一个应用程序收到一个不能识别的多部分子类型,这个应用程序必须将它视为"multipart/mixed"。
注:"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 = <the OCTETs making up the field-value
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-Encoding)指明的传输编码(transfer-coding)应用于实体主体(entity-body)时才和实体主体相区别,其它情况消息主体和实体主体相同。传输译码头域在14.41节阐述。
message-body=entity-body|<entity-body encoded as per Transfer-Encoding>
传输译码头域被用来指明应用程序的传输编码,它是为了保证消息的安全和合适的传输。传输译码(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节)出现,并且它的域值是非”“dentity”传输编码值,那么传输长度(transfer-length)被“块”(chunked)传输编码定义,除非消息因为通过关闭连接而结束。
3。如果出现Content-Length头域(属于实体头域)(见14.13节),那么它的十进制值(以字节表示)即代表实体主体长度(entity-length,译注:实体长度其实就是实体主体的长度,以后把entity-length翻译成实体主体的长度)又代表传输长度(transfer-length)。Content-Length头域不能包含在消息中,如果实体主体长度(entity-length)和传输长度(transfer-length)两者不相等(也就是说,出现Transfer-Encodind头域)。如果一个消息即存在传输译码(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用户代理(user agents)当接收了一个无效的长度时必须能通知用户。
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和协议版本(HTTP-Version),最后以CRLF结束。元素是以SP字符分隔。除了最后的CRLF,CR或LF是不被允许的。
Request-Line =Method SP Request-URL SP HTTP-Version CRLF
5.1.1方法 (Method)
方法标记(token)指明了在被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 * HTTP/1.1
当向代理(proxy)提交请求时,绝对URI(absoluteRUI)格式是不可缺少的。代理(proxy)可能会被要求再次转发请求或者从一个有效的缓存(cache)里构造响应去响应请求。注意:代理可能转发请求给另一个代理或直接给被absoluteURI指定的源服务器。为了避免循环请求,代理(proxy)必须能识别所有的服务器名字,包括任何别名,本地的变化值,数字IP地址。一个请求行(Request-Line)的例子如下:
GET http://www.w3.org/pub/www/TheProject.html HTTP/1.1
为了未来HTTP版本的所有请求能迁移到absoluteURI地址,所有基于HTTP/1.1的服务器必须接受绝对absoluteURI形式的请求,即使HTTP/1.1客户端只为代理产生绝对absoluteURI请求。
authority格式只被用于CONNECT方法(9.9节).
Request-URI大多数情况是被用于指定一个源服务器或网关(gateway)上的资源。这种情况下,URI的绝对路径(abs_path,见3.2.1节)作为Request-URI被传输,并且URI网络位置(authority)必须在Host头域里指出。例如:客户希望直接从源服务器获取资源,这种情况下,它可能会建立一个TCP连接,此连接是特定于主机“www.w3.org”的80端口的,这时会发送下面行:
GET /pub/WWW/TheProject.html HTTP/1.1
Host:www.w3.org
接下来是请求的其他部分。注意绝对路径(absolute path)不能是空的;如果在原始URI里没有出现绝对路径,必须给出"/"(服务器的根)。
Request-URI是以3.2.1节里指定的格式传输。如果Request-URI用"%HEX HEX"[42]编码,源服务器为了解析请求必须能对它进行解码。服务器接收到一个无效的Request-URI时必须以一个合适的状态码响应。
透明代理(proxy)不能重写接收到的Request-URI里的“abs_path”部分,当它转发此请求到下一个内向服务器(inbound server,见1.3术语)时,但除了上面说的把一个空的abs_path用一个”/”代替之外。
注:不重写的规则是为了防止代理(proxy)改变请求的原意,因为存在源服务器利用非保留(non-reserved)的URI字符为相反的目的 。实现者应该知道某些低于HTTP/1.1版本的代理(proxy)会重写Request-URI。
5.2请求资源的识别 (The Resource Identified by a Request)
请求资源的精确定位是由请求里的Request-URI和Host头域决定的。
如果源服务器不允许资源根据请求的不同主机来区分时,那么它可以会忽略Host头域的值,当它决定通过HTTP/1.1请求来识别资源的时候。(在HTTP/1.1里关于对Host的支持在19.6.1.1节描述了其他的要求)。
一个源服务器如果必须基于请求主机来区分资源(这是因为存在虚拟主机(virtual hosts)和虚拟主机名(vanity host names)),那么,对HTTP/1.1请求,它必须遵循下面的规则去决定请求的资源:
1. 如果Request-URI是绝对地址(absoluteURI),那么主机(host)是Request-URI的一部分。任何出现在请求里Host头域的值应当被忽略。
2. 假如Request-URI不是绝对地址(absoluteURI),并且请求包括一个Host头域,则主机(host)由该Host头域的值决定.
3. 假如由规则1或规则2定义的主机(host)对服务器来说是一个无效的主机(host),则应当以一个400(坏请求)错误消息返回。
缺少Host头域的HTTP/1.0请求的接收者可能会尝试去利用启发式的规则(例如:检查URI路径是否是特定某个主机)去决定被请求的真正资源。
5.3请求头域 (Request Header Fields)
请求头域允许客户端传递请求的附加信息和客户端自己的附加信息给服务器。这些头域作为请求的修饰,这和程序语言方法调用的参数语义是等价的。
请求头(request-header) = Accept ;14.1节
| Accept-Charset ;14.2节
|Accept-Encoding ;14.3节
|Accept-Language ;14.4节
|Authorization ;14.8节
|Expect ;14.20节
|From ;14.22节
|Host ;14.23节
|If-Match ;14.24节
|If-Modified-Since ;14.25节
| If-None-Match ;14.26节
| If-Range ;14.27节
| If-Unmodified-Since ;14.28节
| Max-Forwards ;14.31节
| Proxy-Authorization ;14.34节
| Range ;14.35节
| Referer ;14.36节
|TE ;14.39节
| User-Agent ;14.43节
请求头域的名字是能被扩展,但只能随协议版本改变而被扩展。然而新的或实践性的头域可以给定请求头域语义,如果所有通信方都把它看作请求头域。不能识别的头域会被看作实体头域(entity-header)。
6 响应 (Response)
接收和解析一个请求消息后,服务器发出一个HTTP响应消息。
response =Status-Line ;6.1节
*(( general-header) ; 4.5节
| response-header ;6.2节
| entity-header)CRLF) ;7.1节
CRLF
[ message-body ] ;7.2节
6.1 状态行 (Status-Line)
响应消息的第一行是状态行(stauts-Line),由协议版本以及数字状态码和相关的文本短语组成,各部分间用空格符隔开,除了最后的CRLF序列,中间不允许有CR或LF。
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
6.1.1状态码与原因短语 (Status Code and Reason Phrase)
Status-Code元素是一个试图理解和满足请求的三位数字整数码,这些码的完整定义在第十章。原因短语(Reason-Phrase)是为了给出关于状态码的简单的文本描述。状态码用于控制,而原因短语(Reason-Phrase)是让用户便于阅读。客户端不需要检查和显示原因短语。
状态码的第一位数字定义响应类别。后两位数字没有任何分类角色。第一位数字有五种值:
-1xx :报告的 -请求被接收到,继续处理
-2xx :成功 - 被成功地接收(received),理解(understood),接受(accepted)的动作 。
-3xx :重发 - 为了完成请求必须采取进一步的动作。
-4xx :客户端出错 - 请求包括错的语法或不能被满足。
-5xx :服务器出错 - 服务器无法完成显然有效的请求。
下面列举了为HTTP/1.1定义的态码值,和对应的原因短语(Reason-Phrase)的例子。原因短语在这里例举只是建议性的----它们也许被一个局部的等价体代替而不会影响此协议的语义。
Status-Code =
"100" ; 10.1.1节: 继续
|"101" ; 10.1.2节: 转换协议
|"200" ; 10.2.1节: OK
|"201" ; 10.2.2节: 已创建
|"202" ; 10.2.3节: 接受
|"203" ; 10.2.4节: 非权威信息
|"204" ; 10.2.5节: 无内容
|"205" ; 10.2.6节: 重置内容
|"206" ; 10.2.7节: 部分内容
|"300" ; 10.3.1节: 多个选择
|"301" ; 10.3.2节: 永久移动
|"302" ; 10.3.3节: 发现
|"303" ; 10.3.4节: 见其它
|"304" ; 10.3.5节: 没有被改变
|"305" ; 10.3.6节: 使用代理
|"307" ; 10.3.8节 临时重发
|"400" ; 10.4.1节: 坏请求
|"401" ; 10.4.2节: 未授权的
|"402" ; 10.4.3节: 必要的支付
|"403" ; 10.4.4节: 禁用
|"404" ; 10.4.5节: 没有找到
|"405" ; 10.4.6节: 方式不被允许
|"406" ; 10.4.7节: 不接受的
|"407" ; 10.4.8节: 需要代理验证
|"408" ; 10.4.9节: 请求超时
|"409" ; 10.4.10节; 冲突
|"410" ; 10.4.11节: 不存在
|"411" ; 10.4.12节: 长度必需
|"412" ; 10.4.13节;先决条件失败
|"413" ; 10.4.14节: 请求实体太大
|"414" ; 10.4.15节; 请求URI太大
|"415" ; 10.4.16节: 不被支持的媒体类型
|"416" ; 10.4.17节: 请求的范围不满足
|"417" ; 10.4.18节: 期望失败
|"500" ; 10.5.1节: 服务器内部错误
|"501" ; 10.5.2节: 不能实现
|"502" ; 10.5.3节: 坏网关
|"503" ; 10.5.4节: 服务不能获得
|"504" ; 10.5.5节: 网关超时
|"505" ; 10.5.6节: HTTP版本不支持
|扩展码
extension-code =3DIGIT
Reason-Phrase = *<TEXT,excluding CR,LF>
HTTP状态码是可扩展的。HTTP应用程序不需要理解所有已注册状态码的含义,尽管那样的理解是很希望的。但是,应用程序必须了解由第一位数字指定的状态码的类别,任何未被识别的响应应被看作是那个类别的x00状态码,未被识别的响应不能被缓存除外。例如,如果客户端收到一个未被识别的状态码431,则可以安全的认为请求有错,并且它会对待此响应就像它接收了一个状态码是400的响应。在这种情况下,用户代理(user agent)应当把响应的实体展现给用户,因为实体有可能包括人类可读的信息,这些信息也许能解释非正常状态的原因。
6.2响应头域 (Response Header Fields)
响应头域允许服务器传送响应的附加信息,这些信息不能放在状态行(Status-Line)里.。这些头域给出有关服务器的信息以及请求URI(Request-URI)指定资源的更进一步访问信息。
response-header = Accept-Ranges ; 14.5节
|Age ; 14.6节
|Etag ; 14.19节
|Location ; 14.30节
|Proxy-Autenticate ; 14.33节
|Retry-After ; 14.37节
|Server ; 14.38节
|Vary ; 14.44节
|WWW-Authenticate ; 14.47节
响应头域的名字能依赖于协议版本的变化而扩展。然而,新的或者实践性的头域可能会给予响应头域的语义如果通信所有成员都能识别他们并把他们看作响应头域。不被识别的头域被看作实体头域。
7 实体(Entity)
如果不被请求方法或响应状态码所限制,请求和响应消息都可以传输实体。 实体包括实体头域(entity-header)与实体主体(entity-body),而有些响应只包括实体头域(entity-header)。
在本节中的发送者和接收者是否是客户端或服务器,这依赖于谁发送或谁接收此实体。
7.1 实体头域(Entity Header Fields)
实体(entity-header)头域定义了关于实体主体的的元信息,或在无主体的情况下定义了请求的资源的元信息。有些元信息是可选的;一些是必须的。
entity-header = Allow ; Section 14.7
| Content-Encoding ; Section 14.11
| Content-Language ; Section 14.12
| Content-Length ; Section 14.13
| Content-Location ; Section 14.14
| Content-MD5 ; Section 14.15
| Content-Range ; Section 14.16
| Content-Type ; Section 14.17
| Expires ; Section 14.21
| Last-Modified ; Section 14.29
| extension-header
extension-header = message-header
扩展头机制允许在不改变协议的前提下定义额外的实体头域,但不保证这些域在接收端能够被识别。未被识别的头域应当被接收者忽略,且必须被透明代理(transparent proxy)转发。
7.2 实体主体(Entity Body)
由HTTP请求或响应发送的实体主体(如果存在的话)的格式与编码方式应由实体的头域决定。
Entity-body= *OCTET
如4。3节所述,实体主体(entity-body)只有当消息主体存在时时才存在。实体主体(entity-body)从消息主体根据传输译码头域(Transfer-Encoding)解码得到,传输译码用于确保消息的安全和合适传输。
7.2.1类型(Type)
当消息包含实体主体(entity-body)时,主体的数据类型由实体头域的Content-Type和Content-Encoding头域确定。这些头域定义了两层顺序的编码模型:
Entity-body:=Content-Encoding( Content-Type( data) )
Content-Type指定了下层数据的媒体类型。Content-Encoding可能被用来指定附加的应用于数据的内容编码,经常用于数据压缩的目的,内容编码是请求资源的属性。没有缺省的编码。
任一包含了实体主体的HTTP/1.1消息都应包括Content-Type头域以定义实体主体的媒体类型。如果只有媒体类型没有被Content-Type头域指定时,接收者可能会尝试猜测媒体类型,这通过观察实体主体的内容并且/或者通过观察URI指定资源的扩展名。如果媒体类型仍然不知道,接收者应该把类型看作”application/octec-stream”。
7.2.2实体主体长度(Entity Length)
消息的实体主体长度指的是消息主体在被应用于传输编码(transfer-coding)之前的长度。4.4节定义了怎样去确定消息主体的传输长度。
8 连接
8.1 持久连接(Persistent Connection)。
8.1.1目的
在没有持久连接之前,为获取每一个URL指定的资源都必须建立了一个独立的TCP 连接, 这就加重了HTTP服务器的负担,易引起互联网的阻塞。嵌入图片与其它相关数据通常使用户在短时间内对同一服务器进行多次请求。目前针对这些性能问题的分析以及一个原型实现的结果是可以获得的[26][30]。 HTTP/1.1(RFC2068)实现的实践过程和度量展现了一个满意的结果。对其他方法也有了初步探究,如T/TCP [27]。
HTTP持久连接有着诸多的优点:
--- 通过建立与关闭较少的TCP连接,不仅节省了路由器与主机(客户端,服务器,代理,网关,隧道或缓存)的CPU时间,还节省了主机用于TCP协议控制块(TCP protocol control blocks)的内存。
--- HTTP请求和响应能在连接上进行管线请求方式。 管线请求方式能允许客户端执行多次请求而不用等待每一个请求的响应(译注:即客户端可以发送请求而不用等待以前的请求的响应到来后再发请求),并且此时只有一个TCP连接被使用,从而提高了效率,减少了时间。
--- 网络阻塞会被减少,这是由于减少了因TCP连接产生的包的数量并且也由于允许TCP有充分的时间去决定网络阻塞的状态。
--- 因为无须在创建TCP连接时的握手上耗费时间,而使后续请求的等待时间减少。
---HTTP改进的越来越优雅,因为报告错误不需要关闭tcp连接的代价。将来的HTTP版本客户端可以乐观的尝试利用一个新特性,但是如果和老服务器通信时错误被报告,那么就要用旧的语义进行重新尝试。
HTTP实现应该实现持久连接。
8.1.2总体操作
HTTP/1.1 与早期HTTP 版本的一个显著区别在于持久连接是HTTP/1.1的缺省方式。也就是说,除非另有指定,客户端总应当假定服务器会保持持久连接,即便在收到服务器的出错响应时也应如此。
持久连接提供了一种可以由客户端或服务器通知终止TCP连接的机制。利用Connection头域(14。10节)可以产生终止连接信号。一旦出现了终止连接的信号,客户端便不可再向此连接提出任何新请求。
8.1.2.1 协商(Negotiation)
除非请求里Connection头域中包含“close”连接标记(connection-token),HTTP/1.1服务器总可以认为HTTP/1.1 客户端想要维持持久连接(persistent connection)。如果服务器想在发出响应后立即关闭连接,它应当发送一个含“close”的Connection头域。
一个HTTP/1.1客户端可能期望连接一直保持开着,但这必须是基于服务器响应里是否包含一个Connection头域并且此头域里是否包含“close”。如果客户端不想再继续维持连接来发送更多请求,那么它应发送一个值为“close”的Connection头域。
如果客户端或服务器中的任一方在Connection头域里包含“close”,那么那个请求就成为这个连接的最后一个请求。
客户端和服务器不应认为持久连接是低于1.1的HTTP版本所拥有的,除非它被显式地指明。19.6.2节指出了跟HTTP/1.1客户端兼容的更多信息。
8.1.2.2 管线(pilelining)
支持持久连接(persistent conncetion)的客户端可以以管线的方式发送请求(即无须等待响应而发送多个请求)。服务器必须按接收请求的顺序发送响应。
假定以持久连接方式进行连接,并且假定在连接建立后进行管线方式请求的客户端应该准备去重新尝试连接如果首次管线请求方式尝试失败。如果客户端重新去尝试连接,那么,只有在客户端知道连接是持久连接之后,客户端才能进行管线发送请求。如果服务器在响应所有对应的请求之前关闭了连接,客户端必须准备去重新发送请求。
客户端不应该利用非等幂的方法或者非等幂的方法序列(见9.1.2节)进行管线方式的请求。否则一个过早的传输层连接的终止可能会导致不确定的结果。希望发送非等幂方法请求的客户端只有接收了上次它发出请求的响应后才能再次发送请求给服务器。
8.1.3代理 (Proxy Servers)
代理是非常重要的,因为代理正确地实现了Connection头域的属性,这在14.10节指出了。
代理必须分别向它相连的客户端或源服务器(或其他的代理)指明持久连接。每一个持久连接只能应用于一个传输层连接。
代理不能和一个HTTP/1.0客户端建立一个HTTP/1.1持久连接(但是参见RFC2068[33]里的关于许多HTTP/1.1客户端利用Keep-Alive头域的问题的讨论)。
8.1.4实际考虑 (Practical Considerations)
服务器通常有一个时限值,超过一定时间即不再维持处于非活动的连接。代理会选一个较高的值,因为客户端很可能会与同一服务器建立多个连接。持久连接方式的采用对于客户端与服务器来说均未提出任何必须存在超时或给定多长时间的要求。
当客户端或服务器希望超时时, 它应该优雅的去关闭传输连接。客户端与服务器端应始终注意对方是否终止了传输层连接,并适当的予以响应。若客户端或服务器未能及时检测到对方已终止了连接,将会造成不必要的网络资源浪费。
客户端,服务器,或代理可能在任意时刻会终止传输连接。比如,客户端可能正想发出新的请求,而此时服务器却决定关闭“闲置”的连接。在服务器看来,连接已经因为闲置被关闭了, 但客户端认为我正在请求。
这表明客户端,服务器与代理必须有能力从连接的异步终止事件中恢复。只要请求是等幂的(见9.1.2节),客户端软件应该能重新打开传输层连接并重试传输遗弃的请求序列而不需要用户进行去交互。对非等幂方法的请求就不能自动重试请求,尽管用户代理(user agent)可能提供一个人工操作去重试这些请求。用户代理(user-agent)对应用程序语义理解的确认应该替代用户的确认。如果再次重试请求序列失败,那么就不能再进行自动重试请求了。
服务器尽可能应该至少在每次连接中响应一个请求。除非出于网络或客户端的故障,服务器不应在传送响应的中途断开连接。
使用持久连接的客户端应限制与某一服务器同时连接的个数。单用户客户端不应与任一服务器或代理保持两个以上的连接。代理应该与其它服务器或代理之间维护2*N个连接,其中N是同时在线的用户数。这些准则是为了改善响应时间和和避免阻塞。
8.2 消息传送的要求(Message Transmission Requirements)
8.2.1持久连接与流量控制 (Persistent Connections and Flow Control)
HTTP/1.1服务器应保持持久连接并使用TCP流量控制机制来解决临时过载,而不是在终止连接后指望客户端的重试。后一方法会恶化网络阻塞。
8.2.2监视连接中出错状态的消息
HTTP/1.1(或更新)客户端应该当在发送请求的消息主体时同时监视网络连接是否处于出错状态。若客户端发现了错误,它应当立即停止消息主体的的传送。若消息主体是以块传输编码方式发送的(3.6节),可以用长度为零的块和空尾部(trailer)来提前标记报文结束。若消息主体之前有Content-Length头域,那么客户端必须关闭连接。
8.2.3 100状态码的用途
100状态码(继续,见10.1.1节)的目的在于允许客户端,在发送此请求消息主体前,判定服务器是否愿意接受发送消息的主体(基于请求的头域)。 在有些情况下,如果服务器拒绝查看消息主体,这时客户端发送消息主体是不恰当的或会大大降低效率。
HTTP/1.1客户端的要求:
--- 若客户端想要在发送请求消息主体之前等候100(继续)响应,则它必须发送一个Expect请求头域(见14.20节),并且值是“100-continue”。
--- 客户端不能发送一个值是“100-continue”的Expect请求头域,如果此客户端不打算发送带消息主体的请求。
由于存在旧实现,协议允许二义性的情形存在,这在客户端在发送“Expect:100-continue”后而不一定要接收一个417(期望失败)状态码或着100(继续)状态码时。因此,当一个客户端发送Expect请求头域给一个源服务器(可能通过代理),此服务器也没有以100(继续)状态码响应,那么客户端不应该在发送请求消息的主体前无限等待。
HTTP/1.1源服务器的要求:
--- 当接收一个包含值为“100-contitue”的Expect请求头域的请求时,源服务器必须或者以100(继续)状态码响应从而继续从输入流里接收数据,或者以一个最终的状态码响应。源服务器不能在发送100(继续)状态码响应之前接收请求主体。如果服务器以一个终结状态码响应后,它可能会关闭传输层连接或者它也可能会继续接收或遗弃剩余的请求。但是既然它返回了一个终结状态码的响应,它就不能再去执行那个请求的方法(如:POST方法,PUT方法)。
--- 如果请求消息不含值为“100-continue”的Expect请求头域, 源服务器不应发送100(继续)响应,并且,当请求来自HTTP/1.0(或更早)的客户端时,服务器也不得发送100(继续)响应。对此规定有一例外:为了与RFC 2068兼容,源服务器可能会发送一个100(继续)状态响应以响应HTTP/1.1的PUT或POSt请求,虽然这些请求中没有包含值为”100-continue”的Expect请求头域。这个例外的目的是为了减少任何客户端因为等待100(继续)状态响应的延时,但此例外只能应用于HTTP/1.1请求,并不适合于其他HTTP版本的请求。
--- 若源服务器已经接收到部分或全部请求的消息的主体,源服务器可以不需要发100(继续)响应。
---一旦请求消息主体被接收和被处理,发送100(继续)响应的源服务器必须最终能发送一个终结状态响应,,除非源服务器过早切断了传输层连接。
--- 若源服务器接收到不含值为“100-contitue”的Expect请求头域的请求,但该请求含有请求消息主体,而服务器在从传输层连接上接收整个请求消息主体前返回一个终结状态响应,那么此源服务器不能关闭传输层连接直到它接收了整个请求或者直到客户端关闭了此连接。否则客户端可能不会信任接收此响应消息。然而,这一要求不应该被解释为防止服务器免受拒绝服务攻击,或者防止服务器被客户端攻击。
对HTTP/1.1代理的要求:
--- 若代理接到一个请求,此请求包含值为“100-continue”的Expect请求头域,并且代理可能不能确定下一站服务器是否遵循HTTP/1.1或更高版协议,那么它必须转发此请求时包含此Expect头域。
--- 若代理知道下一站服务器版本是HTTP/1.0或更低,则它不能转发此请求,并且它必须以417(期望失败)状态响应。
--- 代理应当维护一个缓存,以记录最近访问下一站点服务器的HTTP版本号。
--- 若接收到的请求来自于版本是HTTP/1.0(或更低)的客户端,并且此请求不含值为“100-continue”的Expect请求头域,那么代理不能转发100(继续)响应。 这一要求可覆盖1xx响应转发的一般规则(参见10.1节)。
8.2.4服务器过早关闭连接时客户端的行为
如果HTTP/1.1 客户端发送一条含有消息主体的请求消息,但不含值为“100-continue”的Expect请求头域,并且如果客户端没有直接与HTTP/1.1源服务器相连,并且客户端在接收到服务器的状态响应之前看到了连接的关闭,那么客户端应该重试此请求。在重试时,客户端可以利用下面的算法来获得可靠的响应。
1. 向服务器发起一新连接。
2. 发送请求头域。
3. 初始化变量R,使R的值为通往服务器的往返时间的估计值(比如基于建立连接的时间),或在无法估计往返时间时设为一常数值5秒。
4. 计算T=R*(2**N),N为此前重试请求的次数。
5. 等待服务器出错响应,或是等待T秒(两者中时间较短的)。
6. 若没等到出错响应,T秒后发送请求的消息主体。
7. 若客户端发现连接被提前关闭,转到第1步,直到请求被接受,接收到出错响应,或是用户因不耐烦而终止了重试过程。
在任意点上,客户端如果接收到服务器的出错响应,客户端
--- 不应再继续发送请求, 并且
--- 应该关闭连接如果客户端没有完成发送请求消息。
9 方法定义(Method Definitions)
HTTP/1.1常用方法的定义如下。虽然方法可以被展开,但新加的方法不能被认为与扩展客户端和服务器共享同样的语义。
Host请求头域(见14.23节)必须能在所有的HTTP/1.1请求里出现。
9.1 安全和等幂(Idempotent)方法
9.1.1安全方法(Safe Methods)
实现者应当知道软件是代表用户在互联网上进行交互,并且应该小心地允许用户知道任何它们可能采取的动作(action),这些动作可能给他们自己或他人带来无法预料的结果。
GET和HEAD方法只是执行没有影响的动作那就是获取资源。这些方法应该被考虑是“安全”的。可以让用户代理调用的其它方法,如:POST,PUT,DELETE,这些方法是特殊的,用户代理应该知道这些方法可能会执行不安全的动作。
自然的,保证当服务器由于执行GET请求而不能产生副作用是不可能的;实际上,一些动态的资源会考虑这个特性。用户并没有请求这些副作用,因此这些副作用对用户应该是不受影响的。
9.1.2等幂方法(Idempotent Mehtods)
方法可以有等幂的性质因为(除了出错或终止问题)N>0个相同请求的副作用同单个请求的副作用的效果是一样(译注:等幂就是值不变性,相同的请求得到相同的响应结果,不会出现相同的请求出现不同的响应结果)。方法GET,HEAD,PUT,DELETE都有这种性质。同样,方法OPTIONS和TRACE不应该有副作用,因此具有内在的等幂性。然而,有可能有多个请求的请求序列是不等幂的,即使在那样的序列中所有方法都是等幂的。(如果整个序列整体的执行的结果总是相同的,并且此结果不会因为序列的整体,部分的再次执行而改变,那么此序列是等幂的。)例如,一个序列是非等幂的如果它的结果依赖于一个值,此值在以后相同的序列里会改变。
根据定义,一个序列如果没有副作用,那么此序列是等幂的(假设在资源集上没有并行的操作)。
9.2 OPTIONS(选项)
OPTIONS方法表明请求想得到请求/响应链上关于此请求里的URI(Request-URI)指定资源的通信选项信息。此方法允许客户端去判定请求资源的选项和/或需求,或者服务器的能力,而不需要利用一个资源动作(译注:使用POST,PUT,DELETE方法)或一个资源获取(译注:用GET方法)方法。
此方法的响应是不能缓存的.。
如果OPTIONS请求消息里包括一个实体主体(当请求消息里出现Content-Length或者Transfer-Encoding头域时),那么媒体类型必须通过Content-Type头域指明。虽然此规范没有定义如何使用此实体主体,将来的HTTP扩展可能会利用OPTIONS请求的消息主体去得到服务器得更多信息。一个服务器如果不支持OPTION请求的消息主体,它会遗弃此请求消息主体。
如果请求URI是一个星号("*"),,OPTIONS请求将会应用于服务器的所有资源而不是特定资源。因为服务器的通信选项通常依赖于资源,所以”*”请求只能在“ping”或者“no-op”方法时才有用;它干不了任何事情除了允许客户端测试服务器的能力。例如:它能被用来测试代理是否遵循HTTP/1.1。
如果请求URI不是一个星号("*"),,OPTIONS请求只能应用于请求URI指定资源的选项。
200响应应该包含任何指明选项性质的头域,这些选项性质由服务器实现并且只适合那个请求的资源(例如,Allow头域),但也可能包一些扩展的在此规范里没有定义的头域。如果有响应主体的话也应该包含一些通信选项的信息。这个响应主体的格式并没有在此规范里定义,但是可能会在以后的HTTP里定义。内容协商可能被用于选择合适的响应格式。如果没有响应主体包含,响应就应该包含一个值为“0”的Content-Length头域。
Max-Forwards请求头域可能会被用于针对请求链中特定的代理。当代理接收到一个OPTIONS请求,且此请求的URI为absoluteURI,并且此请求是可以被转发的,那么代理必须要检测Max-Forwards头域。如果Max-Forwards头域的值为“0”,那么此代理不能转发此消息;而是代理应该以它自己的通信选项响应。如果Max-Forwards头域是比0大的整数值,那么代理必须递减此值当它转发此请求时。如果没有Max-Forwards头域出现在请求里,那么代理转发此请求时不能包含Max-Forwards头域。
9.3 GET
GET方法意思是获取被请求URI(Request-URI)指定的信息(以实体的格式)。如果请求URI涉及到一个数据生成过程,那么这个过程生成的数据应该被作为实体在响应中返回而不是过程的源文本,除非源文本恰好是过程的输出。
如果请求消息包含 If-Modified-Since,,If-Unmodified-Since,If-Match,If-None-Match或者 If-Range头域,GET的语义将变成“条件(conditionall) GET”。一个条件GET方法会请求满足条件头域的实体。条件GET方法的目的是为了减少不必要的网络使用,这通过允许利用缓存里仍然保鲜的实体而不用多次请求或传输客户端已经拥有的实体来实现的。.
如果请求方法包含一个Range头域,那么GET方法就变成“部分Get”(partial GET)方法。一个部分GET会请求实体的一部分,这在14.35节里描述了。 部分GET方法的目的是为了减少不必要的网络使用,可以允许客户端从服务器获取实体的部分数据,而不需要获取客户端本地已经拥有的部分实体数据。
GET请求的响应是可缓存的(cacheable)如果此响应满足第13节HTTP缓存的要求。
看15.1.3节关于GET请求用于表单时安全考虑。
9.4 HEAD
HEAD方法和GET方法一致,除了服务器不能在响应里返回消息主体。HEAD请求响应里HTTP头域里的元信息(译注:元信息就是头域信息)应该和GET请求响应里的元信息一致。此方法被用来获取请求实体的元信息而不需要传输实体主体(entity-body)。此方法经常被用来测试超文本链接的有效性,可访问性,和最近的改变。.
HEAD请求的响应是可缓存的,因为响应里的信息可能被缓存用于更新以前那个资源对应缓存的实体.。如果出现一个新的域值指明缓存的实体和当前源服务器上的实体有所不同(可能因为Content-Length,Content-MD5,ETag或Last-Modified值的改变),那么缓存(cache)必须认为缓存项是过时的(stale)。
9.5 POST
POST 方法被用于请求源服务器接受请求中的实体作为请求资源的一个新的从属物。POST被设计涵盖下面的功能。
--已存在的资源的注释;
--发布消息给一个布告板,新闻组,邮件列表,或者相似的文章组。
--提供一个数据块,如提交一个表单给一个数据处理过程。
--通过追加操作来扩展数据库。
POST方法的实际功能是由服务器决定的,并且经常依赖于请求URI(Request-URI)。POST提交的实体是请求URI的从属物,就好像一个文件从属于一个目录,一篇新闻文章从属于一个新闻组,或者一条记录从属于一个数据库。
POST方法执行的动作可能不会对请求URI所指的资源起作用。在这种情况下,200(成功)或者204(没有内容)将是适合的响应状态,这依赖于响应是否包含一个描述结果的实体。
如果资源被源服务器创建,响应应该是201(Created)并且包含一个实体,此实体描述了请求的状态。并且引用了这个新资源和一个Location头域(见14.30节)。
POST方法的响应是不可缓存的。除非响应里有合适的Cache-Control或者Expires头域。然而,303(见其他)响应能被用户代理利用去获得可缓存的响应。
POST 请求必须遵循8.2节里指明的消息传送的要求。
参见15.1.3节关于安全性的考虑.
9.6 PUT
PUT方法请求服务器去把请求里的实体存储在请求URI(Request-URI)标识下。如果请求URI(Request-URI)指定的的资源已经在源服务器上存在,那么此请求里的实体应该被当作是源服务器关于此URI所指定资源实体的最新修改版本。如果请求URI(Request-URI)指定的资源不存在,并且此URI被用户代理定义为一个新资源,那么源服务器就应该根据请求里的实体创建一个此URI所标识下的资源。如果一个新的资源被创建了,源服务器必须能向用户代理(user agent) 发送201(已创建)响应。如果已存在的资源被改变了,那么源服务器应该发送200(Ok)或者204(无内容)响应。如果资源不能根据请求URI创建或者改变,一个合适的错误响应应该给出以反应问题的性质。实体的接收者不能忽略任何它不理解和不能实现的Content-*(如:Content-Range)头域,并且必须返回501(没有被实现)响应。
如果请求穿过一个缓存(cache),并且此请求URI(Request-URI)指示了一个或多个当前缓存的实体,那么这些实体应该被看作是旧的。PUT方法的响应是不可缓存的。
POST方法和PUT方法请求最根本的区别是请求URI(Request-URI)的含义不同。POST请求里的URI指示一个能处理请求实体的资源(译注:此资源可能是一段程序,如jsp里的servlet) 。此资源可能是一个数据接收过程,一个网关(gateway,译注:网关和代理的区别是:网关可以进行协议转换,而代理不能,只是起代理的作用,比如缓存服务器其实就是一个代理),或者一个单独接收注释的实体。对比而言,PUT方法请求里的URI标识请求里封装的实体一一用户代理知道URI意指什么,并且服务器不能把此请求应用于其它资源(resource)。如果服务器期望请求被应用于一个不同的URI,那么它必须发送301(永久移动)响应;用户代理可以自己决定是否重定向请求。
一个单独的资源可能会被许多不同的URI指定。如:一篇文章可能会有一个URI指定当前版本,而这个URI区别于这篇文章其它特殊版本的URI。这种情况下,对一个通用URI的PUT请求可能会导致其资源的其它URI请求被源服务器重定义。
HTTP/1.1没有定义PUT方法对源服务器的状态影响。
PUT请求必须遵循8.2节中的消息传送的要求。
除非特别指出,PUT方法请求里的实体头域应该被用于资源的创建或修改。
9.7 DELETE(删除)
DELETE方法请求源服务器删除请求URI指定的资源。此方法可能会在源服务器上被人为的干涉(或通过其他方法)。客户端不能保证此操作能被执行,即使源服务器返回成功状态码。然而,服务器不应该指明成功除非它打算删除资源或把此资源移到一个不可访问的位置。
如果响应里包含描述成功的实体,响应应该是200(OK);如果DELETE动作还没有执行,应该以202(已接受)响应;如果DELETE请求方法已经执行但响应不包含实体,那么应该以204(无内容)响应。
如果请求穿过缓存,并且请求URI(Request-URI)指定了一个或多个缓存当前实体,那么这些缓存项应该被认为是旧的。DELETE方法的响应是不能被缓存的。
9.8 TRACE
TRACE方法被用于激发一个远程的,应用层的请求消息回路(译注:TRACE方法让客户端测试到服务器的网络通路,回路的意思如发送一个请返回一个响应,这就是一个请求响应回路,)。最后的接收者也许是源服务器,也许是接收到包含Max-Forwards头域值为0请求的代理或网关。TRACE请求不能包含一个实体。
TRACE方法允许客户端去了解数据被请求链的另一端接收的情况,并且利用那些数据信息去测试或诊断。Via头域值(见14.45)有特殊的用途,因为它可以作为请求链的跟踪信息。利用Max-Forwards头域允许客户端限制请求链的长度,这是非常有用的,因为可以利用此去测试代理链在无限循环里转发消息。
如果请求是有效的,响应应该在实体主体里包含整个请求消息,并且响应应该包含一个Content-Type头域值为”message/http”的头域。此方法的响应不能被缓存。
9.9 CONNECT(连接)
HTTP1.1协议规范保留了CONNECT方法,此方法是为了能用于能动态切换到隧道的代理((如 SSL tunneling [44]).)。
10.状态码定义
每一个状态码在下面定义,包括此状态码依赖于方法的描述和响应里需要的任何元信息的描述。
10.1 通知的 1xx
这类状态代码指明了一个临时性的响应,包含一个Status-Line和可选的头域,并且被一个空行结束(译注:空行就是CRLF)。这类状态码响应没有必须的头域。因为HTTP/1.0没有定义任何1xx状态码,所以服务器不能发送一个1xx响应给一个HTTP/1.1客户端,除了实验性的目的。
客户端必须能在一个常规响应之前接受一个或多个1xx状态,即使客户端不期望100(继续)状态响应。不被客户端期望的1xx状态响应可能会被用户代理忽略。
代理必须能转发1xx响应,除非代理和它的客户端的连接关闭了,或者除非代理自己响应请求并产生1xx响应。(例如:如果代理添加了“Expect:100-continue”头域当转发请求时,那么它不必转发相应的100(继续)状态响应。)
10.1.1 100 继续 (Continue)
100状态响应告诉客户端应该继续请求。100响应是个中间响应,它被用于通知客户端请求的初始部分已经被接收了并且此请求还没有被服务器丢弃。客户端应该继续发送请求的剩余部分,或者,如果此请求已经完成了客户端会忽略此100响应。服务器在接收请求后必须发送一个终结响应。见8.2.3节关于此状态码的讨论和使用。
10.1.2 101切换协议 (Switching Protocols)
服务器理解和愿意遵循客户端这样的请求,此请求通过Upgrade消息头域(见14.42节)指明在连接上应用层协议的改变。 服务器将会切换到响应里Upgrade头域里指明的协议,它会以一个空行结束此101响应。
只有协议切换时能受益协议才应该切换。例如,当传输资源时,切换到一个新的HTTP版本比旧的版本要好,或者切换到一个实时的,同步的协议会带来好处时,这时我们都应该考虑切换。
10.2 成功 2xx
这类状态码指明客户端的请球已经被服务器成功的接收,理解,并且接受了。
10.2.1 200 OK
此状态码指明客户端请求已经成功了。响应返回的信息依赖于请求里的方法,例如:
GET 请求资源的相应的实体已经包含在响应里并返回给客户端。
HEAD 相应于请求资源实体的实体头域已经被包含在无消息主体的响应里。
POST 响应里已经包含一个实体,此实体描述或者包含此POST动作执行的结果
TRACE 响应里包含一个实体,此实体包含终端对服务器接收的请求消息。
10.2.2 201 已创建(Created)
请求已经被服务器满足了并且已经产生了一个新的资源。新创建的资源的URI在响应的实体里返回,但是此资源最精确的URI是在Location头域里给出的。响应应该含有一实体,此实体包含此资源的特性和位置,用户或用户代理能从这些特性和位置里选择最合适的。实体格式被Content-Type头域里媒体类型指定。源服务器必须能在返回201状态码之前建立资源。如果动作(译注:这里指能创建资源的方法,如POST方法)不能被立即执行,那么服务器应该以202(接受)响应代替。
一个201响应可以包含一个ETag响应头域,此头域的值指明了当前请求变量(译注:变量的含义见第1.3节“变量”的解释)也即刚刚创建的资源的实体标签(entity tag)值,见14.19节。
10.2.3 202 接受(Accepted)
请求已经被接受去处理,但是还没有处理完成。请求可能会或者不会处理完成,因为存在当处理的过程中拒绝处理的情况。
202响应是有意非担保性的。它是为了允许服务器可以为其它处理(如:每天执行一次的批处理)接收请求而不需要用户代理在处理没有完成之前长期连接到服务器。响应里的实体应该包含请求当前状态的声明并且应该包含一个状态监视指针或一些用户期望何时请求被满足的评估值。
10.2.4 203 非权威信息(Non-Authoritative information)
此状态码响应指明响应里实体头域元信息不能从源服务器获而是从本地的或第三方响应副本里收集的。这些元信息可能是源服务器版本的子集或超集。如,包含一个存在本地的资源注释信息就可以产生一个源服务器能理解的元信息的超集。利用此响应状态码不是必须但是比200(Ok)响应却更加合适。
10.2.5 204 无内容 (No Content)
服务器已经满足了请求但并没有返回一个实体而是返回更新的元信息。此响应可能包含新的或更新的元信息以实体头域的形式,这些元信息应该相关于请求变量。
利用此204响应,客户端如果是一个用户代理,它就可以不用改变引起请求发送的文档视图(译注:如一篇html文档在浏览器里呈现的样子)。204状态响应主要的目的是允许输入,而不必引起用户代理当前文档视图的改变,尽管一些新的或更新了的元信息可能会应用于用户代理视图里的当前文档。
204响应不能包含一个消息主体,并且在头域后包含一个空行结束。
10.2.6 205 重置内容(Reset Content)
205状态响应是服务器告诉用户代理应该重置引起请求被发送的文档视图。此响应主要的目的是清空文档视图表单里的输入框以便用户能输入其它信息。此响应不能包含一个实体。
10.2.7 206 部分内容(Partial Content)
服务器已经完成了客户端对资源的部分GET请求。请求必须包含一个Range头域(14.35节)用来指出想要的范围,并且也有可能包含一个If-Range头域(见14.27节)来使请求成为一个条件请求。
206状态的响应必须包含以下的头域:
- 或者含有一个Content-Range头域,此头域指明了响应里的范围;或者含有一个值为“multipart/byteranges”的Content-Type头域并且每部分包含Content-Range头域。如果一个Content-Length头域出现在响应里,它的值必须是实际传输的消息主体的字节数。
- Date头域
- ETag 和/或 Content-Location头域,如果这些头域假设在相同请求的200响应里也会出现的话。
- Expire,Cache-Control,和/或者Vary头域,如果这些头域的域值与以前同一变量响应中的不一样。
如果206响应是使用了强缓存验证(见13.3.3)的If-Range请求的结果,那么此响应不应该包含其他的实体头域。如果响应是使用了弱缓存验证的If-Range请求的结果,那么响应必须不能包含其他的实体头域;这能防止缓存里缓存的实体主体与更新头域之间的不一致性。另外,响应必须包含假设在相同请求的200响应里的所有实体头域。
缓存不能把206响应和以前的缓存内容相合并如果ETag或Last-Modified头域并不能精确匹配,见13.5.4。
一个不能支持Range和Content-Range头域的缓存不能缓存206(部分的)响应。
10.3 重新定向 3xx.
这类状态码指明用户代理需要更进一步的动作去完成请求。进一步的动作可能被用户代理自动执行而不需要用户的交互,并且进一步动作请求的方法必须为GET或HEAD。一个客户端应该发现无限的重定向循环,因为此循环能产生网络拥挤。
注意:以前此规范版本建议一个最多能有五个重定向。内容开发者应该知道客户端可能存在这个限制。
10.3.1 300 多个选择.(Multiple Choices)
请求资源对应于众多表现形式中的一个,每个表现形式都有一个特定的位置(location),并且代理驱动协商(agent-driven negotiation)信息(见13章)被提供以便用户(或用户代理)能选择一个更适的表现形式并重定向它的请求到那个表现形式的位置。
除非是HEAD请求,否则300状态响应应该包含一个实体,此实体包含一个资源特性和位置列表,从这个列表里用户或用户代理能选择最合适的资源的表现形式。实体格式被Content-Type头域里的媒体类型指定。用户代理选择最合适的表现形式的行为可能会被自动执行,这依赖于实体格式和自己的能力。然而,此规范并没有定义自动执行行为的标准。
如果服务器能确定更好的表现形式,它应该为此表现形式在Location头域里包含一个特定的URI来指明此表现形式的位置;用户代理可能会利用此Location头域自动重定向。300状态响应是可缓存的除非被特别指明。
10.3.2 301 永久移动 (Moved Permanently)
请求资源被赋于一个新的永久的URI,并且任何将来对此资源的引用都会利用此301状态响应返回的URI。具有链接编辑能力的客户端应该能自动把请求URI的引用转到到服务器返回的新的引用下。此响应是能缓存的除非另外声明。
新的永久URI应该在响应中被Location头域给定。除非请求方法是HEAD,否则此响应应该包含一个超文本提示和一个指向新URI的超文本链接。
如果客户端接收了一个来自非GET或HEAD请求方法的301响应,那么用户代理不能自动重定向请求除非它能被用户确认,因为这可能会改变请求提交的条件。
注意:当客户端在接收了301状态码响应后,会重定向POST请求,一些已经存在的HTTP/1.0用户代理会错误的把此请求变成一个GET请求。
10.3.3 302 发现(Found)
请求的资源暂时地存放在一个不同的URI下。因为重定向的地址可能有时会被改变,客户端应该继续为将来的请求利用请求URI(Request-URI)。302响应是只有在Cache-Control或Expires头域指明的情况下才能被缓存。
临时的URI应该在Location头域里指定。除非请求方法是HEAD,否则此响应应该包含一个超文本提示和一个指向新URI的超文本链接。
如果客户端接收了一个来自非GET或HEAD请求方法的302响应,那么用户代理不能自动重定向请求除非它能被用户确认,因为这可能会改变请求提交的条件。
注意:RFC1945和RFC2068指定客户端不能在重定向请求的时候改变请求方法。然而,大多数用户代理实现会把302响应看成是303响应,从而根据Location头域值的URI执行GET请求,不管原始的请求方法是什么。303和307状态响应的目的是为使服务器明白客户端期望哪种类型的重定向。
10.3.4 303 见其他(See Other)
请求的响应被放在一个不同的URI下,并且应该用GET方法获得那个资源。此方法的存在主要是让POST调用脚本的输出能使用户代理重定向到一个选择的资源。新的URI并不是原始请求资源的代替引用。303响应不能被缓存,但是再次重定向请求的响应应该被缓存。
不同的URI应该在Location头域里指定。除非请求方法是HEAD,除非请求方法是HEAD,否则此响应应该包含一个超文本提示和一个指向新URI的超文本链接。
注意:许多HTTP/1.1以前版本的用户代理不能理解303状态响应。当这些客户端比较关注于互操作性的时候,302状态码应该被代替利用,因为大多用户代理对302响应的理解就是303响应。
10.3.5 304 没有改变(Not Modified)
如果客户端已经执行了条件GET请求,并且访问服务器的资源是允许的,但是服务器上的文档并没有被改变,那么服务器应该以此状态码响应。304响应不能包含一个消息主体(message-body),并且在头域后面总是以一个空行结束。
此响应必须包含下面的头域:
- Date,除非14.18.1指明的那些规则下Date是可以遗漏的。如果时钟不准确的源服务器遵循这些规则,并且代理和客户端在接收了一个没有Date头域的响应后加上了自己的Date(这在RFC 2086里声明了,见14.19节),缓存将会正确操作。
- ETag 和/或 Content-Location头域,如果这些头域应在相同请求的200响应里出现的话。
- Expire,Cache-Control,和/或者Vary头域,如果这些头域值与以前同一变量响应中的不一致。
如果条件GET请求使用强缓存验证(见13.3.3节)时,那么响应不应包含其它实体头域。当条件GET使用弱缓存验证时,那么响应必须不能包含其它实体头域;这能防止缓存的实体主体与更新的头域之间的不一致性。
如果一个304响应指示一个没有被缓存的实体,那么此缓存必须不用理会此响应,并且以无条件请求重试请求。
如果缓存利用一个接收到的304响应去更新一个缓存项,那么缓存必须用此响应响应里任何最新的域值更新缓存项。
10.3.6 305 使用代理 (Use Proxy)
请求资源必须能通过代理访问,代理的地址在响应的Location头域里指定。Location头域指定了代理的URI。接收者被期望通过代理重试此请求,305响应必须被源服务器产生。
注意:RFC 2068并没有说明305响应必须重定向一个单独请求并且只能被源服务器产生。不注意这些限制会有重要的安全后果。
10.3.7 306没有使用的(unused)
306状态码被用于此规范以前的版本,是不再使用的意思,并且此状态码被保留。
10.3.8 307临时重发(Temporary Redirect)
请求的资源临时存在于一个不同的URI下。由于重新向可能有时会改变,所以客户端应该继续利用此请求URI(Request-URI)为将来的请求。307响应只有被Cache-Control或Expire头域指明时才能被缓存。
临时URI应该在响应的Location头域里给定。否则此响应应该包含一个超文本提示和一个指向新URI的超文本链接,因为许多HTTP/1.1以前的用户代理不能理解307状态响应。因此,此提示应该包含用户在新的URI上重试原始请求的必需信息。
如果307状态响应.对应的请求的方法不是GET或HEAD,那么用户代理不能自动重定向此请求除非它能被用户确认,因为因为这可能会改变请求提交的条件。
10.4 客户端错误 4xx
状态码4xx类的目的是为了指明客户端出现错误的情况。除了当响应一个HEAD请求,服务器应该包含一个实体,此实体包含一个此错误请求的解释。此状态码对所有请求方法都是适合的。用户代理应该展示任何响应里包含的实体给用户。
如果客户端发送数据,利用TCP的服务器实现应该小心地确保客户端确认包含了响应的包(packets)的接收,在服务器关闭此输入连接前。如果在关闭连接后,客户端继续发送数据给服务器,那么服务器的TCP栈将发送一个重置包给客户端,这能擦除客户端非确认的输入缓冲(input buffers)在这些缓冲被HTTP应用程序读和解析之前。
10.4.1 400 坏请求(Bad Request)
请求不能被服务器理解,由于错误的语法。客户端不应该在没有改变请求的情况下重试请求。
10.4.2 401 未授权的 (Unauthorized)
服务器需要对请求进行用户认证。响应必须包含一个WWW-Authenticate头域(见14.47),此头域包含一个适用于请求资源的授权的激励(challenge)。客户端会以一个Authorization头域重试请求。如果请求包含了授权证书,那么401响应指明对这些证书的授权失败。如果401响应包含一个和以前响应的同样激励,并且用户代理已经尝试至少一次的授权,那么用户应该被呈现包含在响应里的实体,因为这些实体可能包含相关的诊断信息。HTTP授权访问在“HTTP Authentication:Basic and Digest Access Authentication”[43]里解释。
10.4.3 402 必需的支付 (Payment Required)
此状态码为将来的应用保留。
10.4.4 403 禁用 (Forbidden)
服务器理解此请求,但拒绝满足此请求。认证是没有作用的,并且请求不应该被重试。如果请求方法是HEAD并且服务器想让客户端知道请求为什么不能被满足,那么服务器起应该在响应实体里描述此拒绝的原因。如果服务器不希望告诉客户端拒绝的原因,那么404状态码(Not Found)响应将被使用。
10.4.5 404 没有找到(Not Found)
服务器并没有找到任何可以匹配请求URI的资源。没有迹象表明条件是暂时或永久的。410(Gone)状态响应应该被使用,如果服务器通过内部配置机制知道一个旧资源永远不能获得并且也没有转发地址。此状态码通常被使用,当服务器不希望精确指出请求为何被拒绝,或者当没有任何其它响应可用时。
10.4.6 405 方法不被允许(Method Not Allowed)
此状态码表示请求行(Request-Line)里的方法对此资源来说不被允许。响应必须包含一个Allow头域,此头域包含以一系列对此请求资源有效的方法。
10.4.7 406 不可接受的 (Not Acceptable)
根据客户端请求的接受头域(译注:如:Accept, Accept-Charset, Accept-Encoding, 或者 Accept-Language),服务器不能产生让客户端可以接受的响应。
除非是HEAD请求,否则响应应该包含一个实体,此实体应该包含一个可得的实体特性和位置列表,通过它用户或用户代理能选择最合适自己的。实体格式被媒体类型指定。依赖于此格式和用户代理的本身能力,选择最合适的可能会被自动执行。然而,此规范并没有定义自动执行选择的标准。
注意:HTTP/1.1服务器被准许根据请求里的接受头域会返回不可接受的响应。在一些情况下,这可能更倾向于发送一个406响应。用户代理被鼓励观察到来的响应的头域来确定此响应是否是可接受的。
如果响应是不可接受的,用户代理应该暂时停止剩余数据的接收并且询问用户然后去决定进一步的动作。
10.4.8 407 需要代理验证(Proxy Authentication Required)
此状态码和401(Unauthorized)相似,但是指示客户端首先必须利用代理对自己验证。代理必须返回一个Proxy-Authenticate头域(见14.33节),此头域包含一个适用于代理的授权激励。客户端可能利用一个合适的Proxy-Autorization头域去重试此请求(见14.34节)。HTTP访问授权在“HTTP Authentication;Basic and Digest Access Authentication”[43]。
10.4.9 408 请求超时(Request Timeout)
客户端在服务器等待的时间里不能产生请求。客户端可能在以后会重试此请求。
10.4.10 409 冲突 (Confilict)
请求不能完成由于和当前资源的状态冲突。此状态码只被允许出现在期望用户也许能解决此冲并且能重新提交此请求的情况下。响应主体应该包含足够的为用户认识此资源冲突的信息。理想的情况下,响应实体应该包含足够为用户或用户代理解决此问题的信息;然而,这是也许没有可能并且也没有必要。
冲突最可能发生在响应PUT请求的时候。例如,如果版本被使用并且被PUT的实体包含资源的改变,而这些改变会和以前的(第三方的)请求的相冲突,那么服务器应该使用409响应去指明它不能完成此请求。在这种情况下,此响应的实体可能包含这两个版本的差异点,响应的实体格式以Content-Type头域指定。
10.4.11 410 不存在(gone)
请求资源在源服务器上不再可得并且也没有转发地址可用。此条件被认为是永久的。具有链接编辑能力的客户端应该在用户确认后删除请求URI的引用。如果服务器不知道或不容易去确定条件是否是永久的,那么此404(没有发现)状态响应将被代替利用。响应是可缓存的,除非另外申明。
410响应主要的目的是为了web维护任务,这通过告诉接收者资源已经不可得了并且告诉接收者服务器拥有者已经把那个资源的远程连接给移除了。对有时间限制的,推销性的服务,和对不再继续工作在服务器站点人员的资源,这个事件(410响应)是非常普遍的。它不需要把所有长久不可得的资源标记为“gone”或者保持任意长时间—这需要服务器拥有者自己的判断
10.4.12 411 长度必需 (Length Required)
服务器拒绝接受请求里没有包含Content-Length头域的请求。客户端可以重试此请求如果它添加了一个有效的Content-Length头域,此头域值指定了请求消息里消息主体的长度。
10.4.13 412 先决条件失败 (Precondition Failed)
在一个或多个请求头域里指定的先决条件当在服务器上测试为false时返回的响应。此响应允许客户端把先决条件放放到当前资源的元信息(头域数据)之上,这样能防止请求方法被应用于一个非目的性的资源。
10.4.14 413 请求实体太大
服务器拒绝处理请求因为请求实体太大以致达到服务器不愿意去处理。服务器可能关闭此连接去防止客户端继续请求。
如果条件是暂时的,服务器应该包含一个Retry-After头域用来指明此条件是暂时的并且指明客户端应该什么时候重试。
10.4.15 414 请求URI太长(Request-URI Too Long)
服务器拒绝为请求服务因为此请求URI太长了以至于服务器不能解析。这种情况是很少的,只发生在当客户端把POST请求不合适地转换为带有大量查询信息的GET请求时。
10.4.16 415 不被支持的媒体类型(Unsupported Media Type)
服务器拒绝为请求服务,因为请求的实体的格式不能被此方法的请求资源所支持。
10.4.17 416 请求范围不满足 (Requested Range Not Satisfiable)
服务器返回一个此状态码的响应,如果请求包含一个Range请求头域(见14.35节),并且此头域里range-specifier值没有和已选资源的当前extent值重叠,并且请求没有包含一个If-Range请求头域。(对byte-ranges来说,这意味着byte-range-spec的所有first-byte-pos
值大于选择的资源的当前长度)。
当此状态码响应是在byte-range请求返回时,响应应该包含一个Content-Range实体头域用来指定已选资源的当前长度(见14.16节)。响应不能使用multipart/byteranges媒体类型。
10.4.18 417 期望失败(Expectation Failed)
Expect请求头域里指定的希望不能被服务器满足,或者,如果服务器是代理,那么能确定请求不能被下一站(next-hop)服务器满足。
10.5 服务器错误 5xx (Server Error)
这类状态码指明服务器处理请求时产生错误或不能处理请求。除了HEAD请求,服务器应该包含一个实体,此实体用来解释错误,和是否是暂时或长期条件。用户代理应该展示实体给用户。此响应状态码能应用于任何请求方法。
10.5.1 500 服务器内部错误 (Internal Server Error)
服务器遇到了一个意外条件,此条件防止服务器满足此请求。
10.5.2 501 不能实现 (Not Implemented)
服务器没有能力去满足请求。当服务器不能识别请求方法并且不支持它请求资源的时候,这个响应是很合适的。
10.5.3 502 坏网关 (Bad Gateway)
此响应说明:作为网关或代理的服务器从上游(upstream)服务器接收了一个无效的响应。
10.5.4 503 服务不能获得(Service Unavailable)
由于服务器暂时地过载或维护,服务器不能处理请求。这就是说这是暂时条件,此条件将会在一些延时后被减轻。延迟的长度可以在Retry-After头域里指定。如果没有Retry-After被给,那么客户端应该处理此响应就像它处理500响应一样。
注意:503状态码的存在并不是意指服务器当产生过载时必须利用它。一些服务器可能希望拒绝此连接。
10.5.5 504 网关超时(Gateway Timeout)
作为网关或代理的服务器在不能及时地接收一个从URI指定的上游(upstream)服务器(例如:HTTP,FTP,LDAP服务器)或者其他的辅助服务器(例如:DNS服务器)的响应。
注意:当DNS查找超时时,一些部署的代理将会返回400或500响应。
10.5.6 505 HTTP版本不支持 (HTTP version Not Supported)
服务器不能支持,或拒绝支持此HTTP协议版本消息。505响应指明服务器不能或不愿意完成这样的请求,这在3.1中描述了。此响应应该包含一个实体,此实体描述了为什么此协议版本不被支持和其他能被服务器支持的协议版本