HTTP/1.1 协议

来源:互联网 发布:淘宝购物车放多久 编辑:程序博客网 时间:2024/05/18 06:22

基于http协议的在线升级系统

摘要

       做了一个省级项目,由于采用了三层的架构(前端pb,java做web服务),从这些年的项目经验上 来,这种架构有非常严重的缺陷,首先是维护的成本上,很多文章都探讨过瘦客户端的易维护性。但是随着业务的变更,比如增加一个字段这样简单的事情,你的客 户端也必定要作出调整,当然你可以写一定的基础代码来动态的忽略掉简单的功能变更 ,但是还有一个最致命的因素是架构师和程序员不能根除的,那就是bug,并且由于程序员水平的参差不齐,客户端能否真正从业务中剥离出来都很难说。因此, 几乎所有的客户端都不可避免的面临着功能或者是bug修改后的升级。

为什么选择http协议

       不需要很多的水分,我选择采用这种方式的原因主要有,服务器出于安全的考虑安装了硬件防火墙,其他的 各种通讯协议穿越防火墙都存在着难度。当然最重要的是我让他们为我开放端口有一定的难度才是根本。这是体制上的悲哀,同时也是我的动力。另外,我所熟练的 语言是java,而java在web开发上所具有的优势非常明显。

系统原理

 一个系统部署到客户的机器上,通常会拷贝文件到某个分区上,写入注册表(windows系统),启动某些服务。而通常的升级可能会做的就是覆 盖以前的文件,至于其他的动作可能不是必须的,并且如果需要,我们会重新制作安装文件给客户来安装来完成那些动作。因此升级的任务简单说来就是下载,更新 文件。

       升级并不是简单的覆盖,一个大型的信息系统会有非常多的编译文件,例如我们的系统就有数十个pbd文 件,如果单纯的下载所有的文件覆盖,开销是不可以容忍的,不过这种方法也有人在用,我亲眼看到过。只是这需要在网络条件要非常好的情况下,不然上百M的下 载可不是几分钟就能搞定的。所以如何标识文件是否需要下载便是首要的问题:方法是给每个文件一个版本号,让客户端程序根据自身版本号与服务器进行比对来决 定哪些需要升级,这种比对的工作可以由客户端或者服务段完成都可以。初期我选择由客户端来完成这些比对,包括目前的实现都只是支持这种方案,不过我决定后 期会把这种控制权让给服务端来完成。

       我们有二十多个用户(当然,这不指客户端的数目),每个客户都或多或少的要求了自己的东西,而这些要 求都不可能紧紧去用if else去控制程序去实现,所以项目的版本逐渐成一个树形发展,以后或者会增加。维护版本是一项非常繁琐的工作,前期规划不好导致的问题会,在 soursafe上现在不同的版本已经有接近20个了,而且这种分化是不可逆转的,即你增加了版本分支后,后续的功能拓展就使得你必须去分别维护分支上的 代码,这项工作会带来重复性的代码移植和测试工作.罗嗦了这么多只是为了发泄项目管理的不成功会造成资源的浪费,很多人认为我们这种大公司的管理体制一定 很好,但是事实是,种种原因在项目上线后的管理变得一塌糊(初期还能按部就班的做,后期项目就便很快发展成一个烂摊子了).

文件比度

       继续我们的正题,每个客户端都会有一个自己的版本文件,这个文件格式都一样,只是文件数目和版本号有所不同,文件的格式采用了xml,如下:

<?xml version="1.0" encoding="UTF-8"?>

<pbds>

 <pbd name="account_dw.pbd" size="170496" edition="1.01.03" leastTime="2006-11-24 07:32:54.000GMT+08:00"/> 

 <pbd name="account_nvo.pbd" size="22016" edition="1.01.03" leastTime="2006-11-24 07:32:56.000GMT+08:00"/> 

 <pbd name="account_vo.pbd" size="125440" edition="1.01.03" leastTime="2006-11-24 07:32:56.000GMT+08:00"/>

</pbds>

       Name指升级文件名,size指文件大小,edition是版本号, leastTime指更新的时间.前三个是比较重要的, leastTime只是一个参考.服务端也会动态的保持一个客户端的升级配置信息,不过结构略有不同:

<?xml version="1.0" encoding="UTF-8"?>

<pbds>

 <pbd name="account_dw.pbd" size="170496" edition="1.01.03" domain=”default” leastTime="2006-11-24 07:32:54.000GMT+08:00"/> 

 <pbd name="account_nvo.pbd" size="22016" edition="1.01.03" domain=”default” leastTime="2006-11-24 07:32:56.000GMT+08:00"/> 

 <pbd name="account_vo.pbd" size="125440" edition="1.01.03" domain=”update” leastTime="2006-11-24 07:32:56.000GMT+08:00"/>

</pbds>

Element pbd的domain属性决定了改文件从哪个域来下载,前面说过,版本的控制不好造成了这种本地化的分支,这些事情客户不会知道也不需要知道,他们只需要程序能完成自己的功能就好了.

       Pbd还有一个size的属性,这是因为从servlet下载完成时能够比对一下文件是否完全下载, 因为下载是采用了pb的inet组件,所以功能不是很强大,暂时也没有时间允许自己开发一个更好的东西,其实也没有必要过分的追求完美,那样就是把自己前 进的道路弄得更加曲折,就像我开发这个系统的管理模块时,过分追求实现的框架复用性,结果到现在也没有真正交付这个系统,好在这是我自己的,没有项目周期 去限制.对比文件是否下载可以有两种方式,一种是在文件传输或结束时做标志,再就是用我们的size属性,我选择后者,简单而有效.

 

 

基于http/1.1的代理,支持http、https、ftp。 可以作为浏览器、ftp下载工具以及各种聊天软件的代理。
暂时不支持浏览器访问ftp,以后将嵌入ftp引擎,对无DNS设置的服务器支持稍后将给出实现方式

 

 

4 HTTP 消息

4.1 消息类型

HTTP消息由客户端到服务端的请求和服务端到客户端的响应组成。

HTTP-message = Request | Response ; HTTP/1.1 messages

请求和响应信息使用RFC 822 [9]中的通用消息格式来传输实体(消息有效载荷)。两种消息都有一个开始行、零或多个报头域(也被成为报头headers)、一个指定报头域结束的空行以及一个可能的消息主体。

generic-message = start-line

*(message-header CRLF)

CRLF

[ message-body ]

start-line = Request-Line | Status-Line

为了保持鲁棒性,服务段在获取请求行(Request-Line)时应该(SHOULD)忽略接收到的空行,换句话说,如果服务正在信息开始时读取协议流,那么它应该忽略最先接收到的CRLF。一些有缺陷的HTTP/1.0客户端实现会在POST请求之后产生额外的CRLF。需要重复一下,BNF所明确禁止的是,HTTP/1.1绝对不能(MUST NOT)在请求的前后有额外的CRLF。

 

4.2消息报头( Message Headers)

HTTP报头域包括e general-header (section 4.5), request-header (section 5.3), response-header

(section 6.2)和entity-header (section 7.1)等域,都遵循RFC 822 [9]3.1章所给出的通用格式。每个报头域有一个名字和一个紧随其后的“:”以及域值组成。域名字不区分大小写。域值可以(MAY)以任意数目的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>

field-content 不包括开头和结尾LWS:出现在域值非空格字符前后的空白。这些开头或结尾的LWS可以在不改变域值语义的前提下删除。任何出现在field-content之间的LWS可以在解释区值或转向消息流前替换为一个SP。不同域名的报头域的次序并不重要。但是,最好首先发送通用报头域,其次发送请求报头域或者响应报头域,最后发送实体报头域。

只有对应报头域的全部域值被定义为一个逗号分隔的列表时,相同域名的多个消息报头域肯能会出现在一个消息里[例如 #(values)]。必须可能把多个报头域合并成“field-name: field-valu”对而不改变语义,通过向第一个field-value追加后续的值,这些值由一个“,”来间隔。 

由于需要解释组合的域值,所接收的同一域名的报头域的次序是重要的,同样的原因代理不能更改消息投递时域值的顺序。

4.3 消息体(Message Body)

HTTP信息的消息体(如果有)是用来传送请求或响应的实体主体。消息体与实体主体的唯一区别在于是否进行传输编码,编码由传输编码(Transfer-Encoding)域来指定(14.41章)。.

message-body = entity-body

| <entity-body encoded as per Transfer-Encoding>

传输编码必须(MUST)用来指定一些传输编码来由应用程序来确保消息安全与恰当的传输。传输编码是消息而不是实体的属性,因此它可以(MAY)被请求/响应链里的应用增加或者删除。。(但是,3.6章对何时使用什么样的传输编码做出了限制)。

消息里是否有消息体的规则对请求和响应是不同的。

请求的消息头里的Content-Length或者Transfer-Encoding报头域决定了在请求里是否存在消息体。如果文档规定了请求方法不能发送实体主体,那么请求中就不能有消息体。服务端应该对所有消息读取和传递消息体;如果请求方法中不包括对实体主体的定义,处理请求时应该忽略消息体。

对响应消息而言,消息是否有消息体取决于请求方法和响应状态嘛(6.1.1章)。HEAD请求方法的响应不能有消息体,尽管会有实体报头域来表明已经处理过了。所有1xx(报告),204(无内容)和304(无修改)响应不能包含消息体。其他的所有响应需要包含消息体,不过可以是零长度的。

4.4 消息长度(Message Length)

消息的传输长度是指消息体出现在消息里的长度;换句话说是消息经过传输编码后的长度。如果消息包括消息体,那么主体的长度是由以下条件中的一个决定的(顺序优先)

1.         不包含消息体的响应消息(若1xx,204和304响应以及对HEAD请求的响应)通常在报头域后的第一个空行停止读取,进而忽略出现在消息里的实体报头域。

2.         如果存在传输编码报头(14.41章)域并且报头值不为“identity”,传输长度由传输编码“chunked”定义,直到因连接关闭而终止消息。

3.         如果出现Content-Length报头域(14.13章),那么其数值应表示实体和传输长度。如果两者的传毒不一致,那么Content-Length不能被发送(已存在Transfer-Encoding报头域)。如果接收到的消息存在Transfer-Encoding和Content-Length,后者必须被忽略。

4.         如果消息使用媒体类型“multipart/byteranges”并且传输长度没有单独指定,那么由自定界限的媒体类型定义传输长度。媒体类型只能在发送者知道接收者可以解析它的情况下才能使用;1.1客户端请求里出现有分块byte-range指定的Range报头域意味着客户端能够解析multipart/byteranges响应。

不识别multipart/byteranges的1.0代理应该继续推送range报头;同时服务短必须使用本章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,它的域值必须与消息体里的OCTET相匹配。HTTP/1.1用户代理在接收到一个无效的长度时必须通知用户。

4.5通用报头域(General Header Fields)

有一部分报头域对请求和响应有通用性,但是不适应于传递中的实体。这些报头域只使用于传输中的消息。

general-header = Cache-Control ; Section 14.9章

| Connection ;  14.10章

| Date ;  14.18章

| Pragma ;  14.32章

| Trailer ;  14.40章

| Transfer-Encoding ;  14.41章

| Upgrade ;  14.42章

| Via ;  14.45章

| Warning ;  14.46章

通用报头域名字只能同协议版本的改变相结合来扩展。不过,新的或者实验性的报头域可能给予通用报头域的语义,只是这需要所有通讯参与者的承认。未被承认的报头域被作为实体报头域来对待。

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)

请求行以方法标识开始,随后是请求URI和协议版本,最后以CRLF结束。元素之间由SP字符隔开。除最后的CRLF序列外不允许出现CR或者LF。

Request-Line = Method SP Request-URI SP HTTP-Version CRLF

5.1.1方法(Method)

方法标识指定了应用到请求URI指向的资源上的方法,该方法是大小写敏感的。

Method = "OPTIONS" ; Section 9.2

| "GET" ; Section 9.3

| "HEAD" ; Section 9.4

| "POST" ; Section 9.5

| "PUT" ; Section 9.6

| "DELETE" ; Section 9.7

| "TRACE" ; Section 9.8

| "CONNECT" ; Section 9.9

| extension-method

extension-method = token

资源所允许的方法列表可以在Allow报头域指定(14.7章)。响应的返回码也会通知客户端当前某个方法是否应用到资源上,因为允许方法的集合可以动态的修改。如果源服务端可以识别方法但请求资源不允许时,服务端应该返回状态码405(禁止的方法);如果源服务端不识别或实现该方法,则返回501(未实现)。通常的服务端都必须实现GET和HEAD方法。其他的方法是可选的(OPTIONAL);不过上述方法如果被实现,它们必须具备9章所支出的语义。

5.1.2     请求URI(Request-URI)

请求URI是一个统一资源定位符,它指定了请求申请的资源。

Request-URI = "*" | absoluteURI | abs_path | authority

四个选项取决于请求的性质。星号“*”表示请求不应用于特定的资源而是服务端本身,这也只能在方法不需要申请特定的资源时使用。下面是例子:

OPTIONS * HTTP/1.1

如果请求是发向代理的,绝对URI是必须的。代理要传递请求或者从一个有效缓存中返回响应。注意代理可能传递该请求到另外一个代理或者绝对URI指定的服务端。为了杜绝请求死循环,代理必须识别它所有的服务名,包括别名,本地变量和IP地址。下面是请求队列的例子:

GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1

为了能够是将来HTTP版本能够转换绝对URI,所有的HTTP/1.1服务端必须能够接受请求的绝对URI,尽管HTTP/1.1客户端只有来使用代理时才生成绝对URI。

Authority形式只被CONNECT方法使用。(9.9章)

最通用的请求URI形式是莫过于指定一个源服务或者网关的资源。这种情况下必须将URI的绝对路径作为请求URI传输,并且URI的网络地址URI(authority)必须在一个Host请求报头域里传输。例如一个客户端想要直接检索源服务上的资源,它需要创建一个到主机“www.w3.org ”80端口的TCP连接并发送以下队列:

GET /pub/WWW/TheProject.html HTTP/1.1

Host: www.w3.org

后面跟着请求的剩余部分。注意绝对路径不能为空;如果最初的URI为空,那么必须作为“/”给出(服务根目录)。

请求URI按照3.2.1章支出的格式传输。如果请求使用“% HEX HEX编码[42],源服务端必须解码请求URI以便于适当的解释请求。服务端应该对无效的请求URI返回适当的状态码。

透明代理在推送所接收请求URI时不能重写其“abs_path”部分,除非将上面所说的空路径替换为“/”。

注意:禁止重写规则是为了防止当源服务端使用错误的使用非保留字作为保留字时代理改变请求的含义。实现者应该注意到一些早期的HTTP/1.1代理会重写请求URI。

5.2 (请求指定的资源)The Resource Identified by a Request

请求所指定的准确资源是由请求URI和Host报头域共同决定的。

不使用请求的主机来区分资源的源服务端在确定HTTP/1.1请求指定的资源时可以忽略Host报头域。(但是请看一下HTTP/1.1所支持的其他Host需求)。

一个基于请求主机(有时候被称为虚拟主机或者虚拟主机名)区分资源的源服务端必须使用下面的规则来确定HTTP/1.1请求所请求的资源:

1.         如果请求URI是一个绝对URI,主机为请求URI中的主机名部分。请求中的哪些Host报头域值必须被忽略。

2.         如果请求URI不是一个绝对URI,并且请求包括一个Host报头域,那么主机由Host的域值来决定。

3.         如果由以上两种方法确定的主机是无效的,那么响应应该是一个400(错误的请求)错误信息。

缺少Host报头域的HTTP/1.0请求的接收者可以尝试使用启发式(例如检查URI路径看是否有针对特定主机的东西)的的方式来确定正确的请求资源。

5.3请求报头域(Request Header Fields)

请求报头域允许客户端向服务端传递关于请求及客户端自身的附件信息。这些字段相当于请求的修饰符,类似于编程语言中调用方法的参数。

request-header = Accept ; Section 14.1

| Accept-Charset ; Section 14.2

| Accept-Encoding ; Section 14.3

| Accept-Language ; Section 14.4

| Authorization ; Section 14.8

| Expect ; Section 14.20

| From ; Section 14.22

| Host ; Section 14.23

| If-Match ; Section 14.24

| If-Modified-Since ; Section 14.25

| If-None-Match ; Section 14.26

| If-Range ; Section 14.27

| If-Unmodified-Since ; Section 14.28

| Max-Forwards ; Section 14.31

| Proxy-Authorization ; Section 14.34

| Range ; Section 14.35

| Referer ; Section 14.36

| TE ; Section 14.39

| User-Agent ; Section 14.43

请求报头域名字只能同协议版本的改变相结合来扩展。不过,新的或者实验性的报头域可能给予请求报头域的语义,只是这需要所有通讯参与者的承认。未被承认的请求报头域被作为实体报头域来对待。

6 响应(Response)

在接收并解释请求信息后,服务端返回HTTP响应信息。

Response = Status-Line ; Section 6.1

*(( general-header ; Section 4.5

| response-header ; Section 6.2

| entity-header ) CRLF) ; Section 7.1

CRLF

[ message-body ] ; Section 7.2

6.1 状态行(Status-Line)

响应信息的第一行是状态行,依次由协议版本、数字状态码以及与之对应的文本组成,各元素间由空格(SP)分隔。除结尾的CRLF以外不允许出现CR或者LF。

Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF

6.1.1(状态码和原因分析)Status Code and Reason Phrase

状态码元素是一个三位证书码,表示请求是否被理解和满足。这些代码在第10章有详细的定义。原因分析是对状态码的简短的文本描述。状态码是用来自动处理,原因分析则是给人工用户处理的。客户端没有被强制要求去检查和显示原因分析。

状态码的首位定义了响应类别。后两位没有什么类别规则。首位数字有5种取值:

l         1xx:报告-接收请求,继续处理

l         2xx:成功-动作被成功接收、理解和接受。

l         3xx:重定向-为完成请求必须进行下一步动作。

l         4xx:客户端错误-请求有语法错误或者无法实现。

l         5xx:服务端错误-服务端无法实现一个显然有效的请求。

HTTP/1.0的状态代码、相应的原因解释例子在下面给出。这里给出的原因分析只是建议的——它们可以被修改而不会影响协议。

Status-Code =

"100" ; Section 10.1.1: continue

| "101" ; Section 10.1.2: Switching Protocols

| "200" ; Section 10.2.1: OK

| "201" ; Section 10.2.2: Created

| "202" ; Section 10.2.3: Accepted

| "203" ; Section 10.2.4: Non-Authoritative Information

| "204" ; Section 10.2.5: No Content

| "205" ; Section 10.2.6: Reset Content

| "206" ; Section 10.2.7: Partial Content

| "300" ; Section 10.3.1: Multiple Choices

| "301" ; Section 10.3.2: Moved Permanently

| "302" ; Section 10.3.3: Found

| "303" ; Section 10.3.4: See Other

| "304" ; Section 10.3.5: Not Modified

| "305" ; Section 10.3.6: Use Proxy

| "307" ; Section 10.3.8: Temporary Redirect

| "400" ; Section 10.4.1: Bad Request

| "401" ; Section 10.4.2: Unauthorized

| "402" ; Section 10.4.3: Payment Required

| "403" ; Section 10.4.4: Forbidden

| "404" ; Section 10.4.5: Not Found

| "405" ; Section 10.4.6: Method Not Allowed

| "406" ; Section 10.4.7: Not Acceptable

| "407" ; Section 10.4.8: Proxy Authentication Required

| "408" ; Section 10.4.9: Request Time-out

| "409" ; Section 10.4.10: Conflict

| "410" ; Section 10.4.11: Gone

| "411" ; Section 10.4.12: Length Required

| "412" ; Section 10.4.13: Precondition Failed

| "413" ; Section 10.4.14: Request Entity Too Large

| "414" ; Section 10.4.15: Request-URI Too Large

| "415" ; Section 10.4.16: Unsupported Media Type

| "416" ; Section 10.4.17: Requested range not satisfiable

| "417" ; Section 10.4.18: Expectation Failed

| "500" ; Section 10.5.1: Internal Server Error

| "501" ; Section 10.5.2: Not Implemented

| "502" ; Section 10.5.3: Bad Gateway

| "503" ; Section 10.5.4: Service Unavailable

| "504" ; Section 10.5.5: Gateway Time-out

| "505" ; Section 10.5.6: HTTP Version not supported

| extension-code

extension-code = 3DIGIT

Reason-Phrase = *<TEXT, excluding CR, LF>

HTTP状态码可以被扩展。HTTP应用可以不用理解所有注册的状态码,当然很显然理解更好。不过,应用应该理解状态码首位数字指示的类别,并将不识别的响应作为该类别的x00状态码进行处理。另外,不识别的响应不能缓存。例如,如果客户端收到一个不识别的状态码431,它可以明确的知道它的请求有错误然后像接收到一个400状态码那样处理响应。这种情况下,用户代理应将同响应一起返回的实体显示给用户,原因是实体里可能包括异常状态的解释信息。

6.2 响应报头域(Response Header Fields)

响应报头域允许服务端传递那些不能放在状态行里的信息。这些报头域给出了关于服务端和请求URI所指定资源访问情况的信息:

response-header = Accept-Ranges ; Section 14.5

| Age ; Section 14.6Z

| ETag ; Section 14.19

| Location ; Section 14.30

| Proxy-Authenticate ; Section 14.33

| Retry-After ; Section 14.37

| Server ; Section 14.38

| Vary ; Section 14.44

| WWW-Authenticate ; Section 14.47

响应报头域名字只能同协议版本的改变相结合来扩展。不过,新的或者实验性的报头域可能给予响应报头域的语义,只是这需要所有通讯参与者的承认。未被承认的报头域被作为实体报头域来对待。

.

7实体(Entity)

 

请求和响应信息可能(MAY)传输实体,当然可能会由于请求方法或这响应状态码的限制而不传输实体由有实体报头域和实体主题组成,但一些响应可能只含有实体报头域。

从这个角度来看,客户端和服务端都能做为发送者或接收者,这取决于是谁来发送和接收实体。

7.1 实体报头域(Entity Header Fields)

实体报头域定义了有无实体主体,请求资源等元信息。这些元信息中有些是可选(OPTIONA)的,有些是在规范的部分环节中必须的(REQUIRED)。

entity-header = Allow ; 14.7章

| Content-Encoding ; 14.11章

| Content-Language ; 14.12章

| Content-Length ; 14.13章

| Content-Location ; 14.14章

| Content-MD5 ; 4.15章

| Content-Range ; 14.16章

| Content-Type ; 14.17章

| Expires ; 14.21章

| Last-Modified ; 14.29章

| extension-header

extension-header = message-header

扩展代理机制允许定义额外的实体报头域.而不必更改协议,但接收者可能不识别扩展的字段。接收者应该(SHOULD)忽略不能识别的报头域,透明代理则必须(MUST)将其继续推送。

7.2 实体主体(Entity Body)

与HTTP请求或响应一起发送的实体主体(如果存在)的采用实体报头域定义的格式和编码方式。

entity-body = *OCTET

实体主体仅当消息实体存在的时候才会出现在消息中,具体描述请参看4.3章。

实体通过解码可能应用的任意传输编码来从消息主体中获取以保证安全和合适的消息传输。

7.2.1类型(Type)

当消息里包括实体主体时,实体的数据类型由报头域Content-Type和Content-Encoding来决定。它们定义了一个两层的顺序的解码模型:

entity-body := Content-Encoding( Content-Type( data ) )

Content-Type指定了潜在数据的媒体类型。Content-Encoding可能用来指定应用到数据的附件的内容编码,一般是出于数据压缩的目的,那是请求资源的属性。这里没有默认编码

包含实体主体的HTTP/1.1/消息应该有一个Content-Type报头域来定义该主体的媒体类型。只有当Content-Typ报头域没有给粗媒体类型时,接收者可以尝试通过检查消息内容和(或者)指定资源的URI来推测媒体类型。如果还是不能知道媒体类型,接收者应该将其作为“application/octetstream”来处理。

7.2.2实体长度

消息的实体长度是指消息主体在为进行任何编码前的长度。

4.4章定义了消息主题的传输长度是如何决定的。

 

 

 

8 连接(Connections)

8.1持久连接( Persistent Connections)

8.1.1目的

在提出持久连接之前,每获取一个URL都有创建一个单独的TCP连接,不断的加重HTTP服务器的负担并导致网络的拥塞。使用内联的图片或者相关数据常常使得客户端在很短时间内发送众多的请求。问题分析和原型实现的结果的分析已经有了[26][30]。HTTP/1.1的实现的执行体验和测算都有很好的结果[39]。实现方式也都被研究过,例如T/TCP[27]。

持久HTTP连接具有一下优势:

l         通过打卡和关闭更少的TCP连接,节省了路由和主机的CPU耗时,以及TCP协议控制阻塞使用的主机内存。

l         HTTP请求和响应可以在一个连接的基础上管道化。管道技术允许客户端发送多个请求而不用等待响应,使得TCP连接更加高效地使用从而更少的浪费时间。

l         通过减少TCP打开导致的包的消息来减少网络拥塞,通过给TCP充分的时间来确定网络的拥塞状态。

l         HTTP可以进化的更加优美,因为错误可以被报告而不用直接关闭TCP连接。使用高HTTP版本的客户端可能尝试一些新的功能,但是如果与旧版本服务端通信时在有错误报告后用要重试旧的语义。

HTTP实现应该实现持久连接。

8.1.2概述(Overall Operation)

HTTP/1.1和早期HTTP版本最大的不同是持久连接是HTTP连接的默认行为。也就是说,除非有其他的标识,客户端应该假设服务器会持有一个持久连接,即使服务端返回错误的响应。

持久化连接提供了一个机制可以让客户端和服务端给出TCP连接关闭的信号。信号用Connection报头域给出(14.10章)。一旦关闭信号发出,客户端就不能再通过那个连接发送任何请求。

8.1.2.1协商( Negotiation)

一个HTTP/1.1服务端可以假定HTTP/1.1客户端会持有一个持久连接,除非发送的请求里有一个Connection报头域里包括连接符号“close”。如果服务器选择在发送响应后立刻关闭连接,它应该发送一个有关闭连接符号的Connection报头域。

HTTP/1.1客户端可以认为一个连接是始终打开的,但决定其保持打开是基于服务端的响应里是否包含一个有关闭连接符的Connection报头。如果客户端不想在请求之后继续持有连接,那么他应该发送一个有关闭连接符号的Connection报头。

如果客户端或者服务端发送了有关闭符号的Connection报头,那个请求就是连接的最后一次使用。

为了保持持久连接,所有经由连接的消息都必须有一个自定义的消息长度(例如关闭连接所没有定义的那个),4.4章对消息长度有描述。

8.1.2.2流水线( Pipelining)

支持持久连接的客户端可以“管道”其请求(例如发送多个请求而不用等待每个响应)。服务必须按照接收请求的顺序发送响应。

采取持久化连接和在创建连接后立即管道化的客户端应该在其第一次管道化尝试失败时重试其连接。如果客户端进行这样的重试,它在确定连接是持久的之前不能进行管道化。客户端也必须准备好重发那些请求,如果服务端在没有返回相应响应就关闭了连接的话。

客户端不应该使用non-idempotent方法或者non-idempotent方法序列来管道化请求。否则的话,一个传输连接的过早的中止可能会导致不确定的结果。那些想发送non-idempotent请求的客户端应该等到它接收到前一个请求的响应状态码之后再发送请求。

8.1.3代理服务器(Proxy Servers)

代理正确地实现14.10章指出的Connection报头域的属性是非常重要的。

代理服务器必须分别想其连接的客户端和源服务端(或者是另一个代理服务器)通知持久化连接。没一个持久化连接只能应用到一个传输链接上。

代理服务器不能同HTTP/1.0客户端创建一个HTTP/1.1连接。(不过可以看一下RFC 2068

[33]关于一些HTTP/1.0客户端实现的Keep-Alive报头的信息和问题讨论)。

8.1.4实际应用的考虑(Practical Considerations)

服务端通常会有一些超时值,一旦超出之后将不再保持不活动的连接。代理服务器可以设一个大一些的值,因为客户端可能有很多连接经由同一个服务器。持久连接没有对服务端或者客户端的超时长度做出要求。

当一个客户端或者服务端认为超时时它应该给传输连接一个完美的中断。客户端和服务端都应该密切监视对方的传输中断,并做出适当的响应。如果客户端或者服务没有察觉对方的关闭可能会导致不必要的网络资源浪费。

客户端、服务端或者代理可能会在任何时候关闭传输连接。例如一个客户端可能已经发送新请求的同时服务端也决定关闭这个无用的连接。从服务的角度看是在关闭失效的连接,但客户端的角度则是正在发送一个请求。

这意味着客户端、服务端和代理应该有能力从异步连接关闭事件中恢复过来。客户端应该重新打开传输连接并且重发失败了请求序列而不用用户交互,只要请求序列是等价的(idempotent)(参看9.1.2章)不等价的方法或者序列不能自动重发,尽管用户代理可能会提交给用户一个重发请求的选择。有程序语义识别的用户代理可以代理用户做出确认。自动重发在第二次请求失败后不应该继续重复。

服务端应该始至少响应每个连接中的一个请求,如果可能的话。服务端不应该在传输响应的中途关闭连接,除非是网络或者客户端错误。

使用持久连接的客户端应该限制其与给定服务端维持的并行性连接数量。一个单用户保持的域服务器或者代理的连接不应该超过2个。代理应该使用最多2*N个与服务或者代理的连接,这里N是并发的活跃用户的数目。这些指导意见是用来改善HTTP响应时间并避免拥塞。

8.2 消息传输需求Message Transmission Requirements

8.2.1持久连接流控制 Persistent Connections and Flow Control

HTTP/1.1服务端应该保存一个持久连接并使用TCP的流控制机制来解决临时性的重载,而不是终止那些客户可能会重试的连接。后者会加剧网络的拥塞。

8.2.2监控连接中的错误信息Monitoring Connections for Error Status Messages

HTTP/1.1 (或者以后的)客户端在发送消息体时应该监控网络以便在其传输请求是发现错误状态。如果客户端发现了错误的状态,它应该立刻中止消息体的传输。如果消息体是用“”编码的方式传输,一个零长度块和空trailer可以用来提前标识消息的结束。如果消息体已经加上了Content-Length报头,客户端应该关闭连接。

8.2.3状态100的使用 Use of the 100 (Continue) Status

100(继续)状态(参看10.1.1章)的目的是允许一个正在发送有请求主体的请求消息的客户端在发送消息主体之前确定源服务是否接受该请求(取决于请求报头)。在一些情况下,如果服务端不用查看主体就拒绝消息而客户端继续发送消息主体是不合适也是很非常浪费时间的。

对HTTP/1.1客户端的要求:

l         如果客户端在发送请求主体前会等待一个100(Continue)响应,它必须发送一个有“100-continue”预期的请求报头。

l         客户端不能发送一个有“100-continue”请求报头域的请求,如果它不打算发送请求主体。

由于有老版本的实现,协议允许不明确的状态,这样客户端可以发送“Expect: 100-continue”而不用收到417(期望失败)或者100(继续)状态。因此,当客户端发送一个报头域给源服务端(或许经由代理)但未收到100(Continue)状态时,客户端不应该无限等待下去。

对HTTP/1.1源服务端的要求:

l         当接收到一个包含带有“100-continue”期望报头域的请求后,源服务端必须要么返回100(Continue)状态继续读取输入流,要么给出一个最终响应代码。服务端在发出100(Continue)响应之前不能等待请求主体。如果给出的是最终状态码,服务端可以关闭传输连接,也可以继续读取并丢弃请求的剩余部分。服务端不能执行请求的方法,如果它返回的是一个最终状态码。

l         一个源服务端不应该在请求信息里没有“100-contiune”期望报头域的情况下返回100(Continue)响应,如果请求来自HTTP/1.0服务器那么它也不能返回100状态。这个规则有一个例外就是:为了兼容草案2068,服务端可以发送一个100状态响应给一个,没有包含有“100-continue期望请求报头域的HTTP/1.1的PUT或者POST请求。这个例外的目的是为了最小化客户端处理未声明的等待100状态造成的延迟,这只能应用于HTTP/1.1请求,不针对其他HTTP版本。

l         一个源服务应该不再发送一个100响应,如果它已经接收到相应请求的部分或者全部的请求实体。

l         一个发送过100响应的源服务端必须在请求实体接收并处理后发送一个最终状态代码,除非它提前中止了传输连接。

l         如果源服务接收到一个不包括含有“100-continue” 期望值的期望请求报头域,请求包含一个请求实体,并且服务在从传输连接中读取全部请求体之前发送了最终状态码,那么服务端不应该关闭传输连接知道它已经读 取了全部请求,或者知道客户端关闭了连接。否则的话,客户端可能没有可靠地接收响应信息。虽然如此,这个要求不是妨碍服务端防止拒绝服务式攻击或者有严重 缺陷的客户端实现。

对HTTP/1.1代理的要求:

l         如果代理接收到一个包含有“100-continue”期望值的期望请求报头域的请求,并且代理知道下一环服务端是HTTP/1.1或者更高版本,或者不知道下一环服务器HTTTP版本,它必须传递请求,包括期望报头域。

l         如果代理知道下一环服务端是HTTP/1.0或者更低的版本,它必须不转寄请求,并且要返回一个417(期望失败)状态。

l         代理应该缓存最近引用的下一环服务器的HTTP版本号。

l         代理必须不能转寄100响应,如果请求消息来自于HTTP/1.0(或者更早的版本)客户端并且不包含有“100-continue”期望值的期望请求报头域。这个要求不考虑推进1xx响应的一般规则。

8.2.4服务端过早关闭连接后的客户端行为 Client Behavior if Server Prematurely Closes Connection

如果一个HTTP/1.1客户端发送了一个包含请求实体的请求,但是请求不包含有“100-continue”期望值的期望请求报头域,并且如果客户端不是直接连接到一个HTTP/1.1源服务器上,并且如果客户端发现在从服务端接收到任何状态之前连接已经关闭,客户端应该重发这个请求。如果客户端不想重发这个请求,它也可以使用接下来的“binary exponential backoff机制来确定获取一个可好的响应:

1.          创建一个到服务端的新连接

2.          传输请求报头域

3.          用估计服务的反馈时间(例如基于它创建连接所用的时间),或者一个5秒的常值来初始化一个变量R 

4.          计算 T = R*(2**N),N是上一次重试的次数。

5.          等待到从服务返回一个错误响应,或者T秒(两者最先的那个)。

6.          如果没有错误返回,在T秒后传输请求实体。

7.          如果客户端发现连接提前关闭了,返回到步骤1知道请求被接收、接收到错误的响应或者用户不耐烦并中止重试过程。

如果在任一步接收到一个错误的状态,客户端

l         不应该继续并且

l         应该关闭连接,如果它没有完成请求信息的发送。

9方法定义Method Definitions

下面定义了HTTP/1.1通用的方法集合。尽管这个集合是可以扩展的,增加的方法在单独扩展的客户端和服务端里不能共享上述的语义。

Host请求报头域必须存在于所有的HTTP/1.1请求。

9.1 安全和冥等的方法Safe and Idempotent Methods

9.1.1安全的方法Safe Methods

实现者应该知道软件代表用户在其通过因特网进行交互,并且应该小心的让用户知道他们将要采取的动作,这些动作可能会对其自身或者其他参与者有不可预期的影响。

特别指出的是,按照协定GET和HEAD方法不应该有出获取资源以外的能力。这些方法应该被认为是安全的。这就允许用户代理用特殊的方式来表现其他的方法,例如GET、PUT和DELETE,这样用户就可以知道请求的是一个可能不安全的动作。

自然地,不能保证服务端执行GET请求时不会产生副作用;事实上,一定动态资源认为它一个特性。这最重要的区别是用户没有请求副作用,因为不应该让他们承担责任。

9.1.2冥等的方法Idempotent Methods

由于 N>0个相同请求的副作用同一个单独的请求是一样的,方法也可以具有等冥特性。方法GET,HEAD,PUT和DELETE共享这个属性。通用,方法OPTIONS和TRACE应该不会有副作用,也是天生等冥的。

虽 然如此,一些请求的序列可能是非冥等的,即使所有在序列中执行的方法是冥等的。(一个序列是冥等的是指整个序列的一次单独执行结果不会因为重新执行该序列 的全部或者部分而改变。)例如,如果序列的结果依赖于一个可能稍后会在同一个序列中做出修改的值,则该序列是非冥等的。

根据定义,没有副作用的序列是冥等的(前提是没有并发的操作在同一个资源上执行)

9.2 OPTIONS

OPTIONS 表示一个请求来获得关于请求URI指定的请求/响应链上的可用通讯选项信息。这个方法允许客户端自行决定资源相关或者服务端能力的选项和(或)要求,而不用指示一个资源动作或者发起一个资源获取。

这个方法的响应是不可缓存的。

如果OPTIONS请求含有实体主体,那么必须通过一个Content-type域来指定媒体类型。虽然本规范里并没有定义怎样使用这个主体,将来的HTTP版本可能或使用OPTIONS主体对服务端做更详细的查询。如果服务器不支持这样的扩展可以丢弃请求主体。

如果请求URI是一个星号(*), OPTIONS请求只是对服务器自身的一般应用而不是针对特定资源。例如,它可以被用来测试代理对HTTP/1.1的兼容性。

如果请求URI不是星号,那么OPTIONS请求只是申请当与资源通讯时有效的选项。

一个200响应应该包含一些报头域来值标示服务端实现的功能选项或者资源的可用性(若Allow),也肯包含一些本规范里为定义的扩展。响应主体,如果有的话,也应该包含通讯选项的相关信息。这种主体的格式规范没有去定义,但是可能在将来的HTTP扩展里定义。内容协商可能会用来选择适当的响应格式。如果响应不包哈响应主体,那么它应该给出一个域值为“0”的Content-Length域。

Max-Forwards请求报头域可以用来选择请求链中的特定代理。当一个代理收到可以继续传播的绝对URI的OPTIONS请求时,代理必须检查Max-Forwards报头域。如果Max-Forwards报头域的值是零(“0”),代理不能转发消息;取而代之,代理应该响应其自身的通讯选项。如果Max-Forwards域值是一个大于0的整数,代理必须在转发请求时递减这个域值。如果没有Max-Forwards域出现在请求里,转发的请求里也绝不能包含Max-Forwards域值。

9.3 GET

GET方法表示取回请求URI指定的任意信息(实体的表单)。如果请求URI引用了一个数据生产进程,它生成的数据会作为响应的实体返回而不是进程的资源文本,除非文本出现在进程的输出中。

如果请求信息包含If-Modified-Since, If-Unmodified-Since, If-Match, If-None-Match或者 If-Range报头域,那么GET方法的语义将变成“conditional GET。一个条件GET方法请求只有在条件报头域描述的环境下实体才会被传输。条件GET方法允许刷新缓存实体而不用提出多个请求或者传输客户端已经拥有的数据,籍此减少不必要的网络使用。

如果请求信息里包含Range报头域,GET方法的语义会变为“partial GET”。一个部分GET请求只传输实体的一部分,参考14.35章的描述。部分GET方法是通过允许部分获取实体而不用传输客户端已拥有的数据来减少网络的使用。

GET请求的响应可以缓存,条件是当且仅当其符合13章描述的HTTP缓存要求。

参看15.1.14章使用表单时的安全考虑。

9.4 HEAD

除了服务端不能在响应中返回消息体,HEAD方法等同于GET。存在于响应HEAD请求的HTTP报头的元信息也应该同样出现在GET请求的响应里。这个方法可以被用来获取请求所指的实体的元信息而不必传输实体主体本身。这个方法最常用于测试超文本连接的有效性、可访问性以及最近的修改。

如果响应信息可以用来更新一个以前缓存的来自资源的实体,那么HEAD请求的响应是可以缓存的。如果新的域值指出缓存的实体不同于当前的实体(可能是Content-Length, Content-MD5, ETag

或者 Last-Modified的改变),缓存应该将缓存的实体丢弃。

 

9.5 POST

使用POST方法的请求中,源服务端接收附加在请求里的实体,作为请求行里请求URI所指定的隶属资源。POST被设计成具有以下功能的统一方法:

l         声明存在资源;

l         投递消息给一个公告板、新闻组、邮件列表或者类似的主题。

l         提供数据块给一个数据处理进程,如提交表单的结果。

l         通过增加操作来扩充数据库。

POST所提供的实际功能取决于服务端并且通常受制于请求URI。投送的实体从属于URI如同文件从属于拥有它的路径一样,就像一个新的文章从属于它投递的新闻组,或者记录从属于数据库。

POST方法执行的动作可能不会生成可以通过URL可以指定的资源。这种情况下,200(OK)或204(无内容)谁是一个恰当的响应状态,依赖于响应是否包含一个描述结果的实体。

如果服务端已经创建了资源,响应应该是201(Created)并且包含一个描述了请求状态和新资源相关的实体,以及一个Location报头(参看14.30章)。

这个方法的响应是不能缓存的,除非响应包含适当的Cache-Control或者Expires报头域。虽然如此,303 (See Other)响应可以用来引导客户代理来检索一个可缓存的资源。

参看15.1.3章关于安全的建议。

 

9.6 PUT

PUT方法要求附加的实体保存它所提供的请求URI下。如果请求URI提到的是一个已经存在的资源,附加的实体应该被当作现在服务器上已有版本的修改。如果请求URI没有指向一个存在的资源,那么这个URI可以被作为请求的用户代理所定义的一个新资源,而服务器可以使用这个URI创建资源。如果资源被创建,源服务端必须通过201(创建)响应通知客户代理。如果是一个存在的资源被修改,应该发送200(OK)或者204(无内容)响应码来指出请求的成功完成。如果请求URI资源不能创建或者修改,应该返回恰当的错误响应来反映错误的种类。实体接收者不能忽略任何它不识别或者没有实现的Content-*(例如 Content-Range)报头,相反在这种情况它必须返回一个501(未实现)响应。

如果请求通过缓存或者请求指定了一个或多个当前缓存的实体,这些实体应该被丢弃。此方法的响应是不能缓存的。

POST和PUT请求根本的不同源自请求URI的含义不同。POST请求中的URI标识了处理附加实体的资源。那个资源可能是数据接受进程,一个其他协议的网关或者一个允许接收注解的单独的实体。相反,PUT请求里的URI指定了请求附带的实体——用户代理知道URI想要的并且服务端不能试图将请求应用到其它资源上。如果请求希望请求应用到不同的URI上,那么它必须发送一个301(永久转移)响应;关于是否要重定向请求可以由用户代理自己做出决定。

多个不同的URI可能会指定同一个资源。例如,一个主体可能会有一个标识“当前版本”的URI,这跟标识每个特定版本的URI是有区分的。这种情况下,一个普通URI上的PUT请求可能导致源服务定义一些其它的URI。

HTTP/1.1没有定义PUT方法如何影响一个源服务端的状态。

PUT请求必须遵守8.2章给出的消息传输要求。

除非领带指定一个特殊的实体报头,PUT请求里的实体报头应该应用到PUT所创建或修改的资源。

9.7 DELETE

DELETE方法是请求源服务端删除请求URI指定的资源。这个方法可能会被源服务端上人为因素(或者其它手段)重写。客户端不能保证操作会被执行,即使源服务给出的状态码标识动作已经被成功执行。虽然如此,服务端不应该标识成功,除非在响应给出时它已经计划要删除资源或者将其转移到不可访问的位置。

如果响应包含描述状态的实体,成功的响应应该是200(OK),如果动作没有执行则返回202(接受的),或者如果动作已经执行但是响应里不包含实体则返回204(无内容)。

如果请求通过一个缓存或者请求URI标识了一个或多个当前的缓存实体,这些实体应该被丢弃。此方法的响应是不可缓存的。

9.8 TRACE

TRACE方法使用来调用一个远程的应用程序层的请求信息的循环返回。请求的最终接收者应该将接收到的信息作为200响应的实体主体反射回客户端。最终的接收可能是接收到一个源服务端或者是第一个在请求中接收到0值Max-Forwards的代理或网关。TRACE请求不能包含实体。

TRACE允许客户端查看请求链的另一端接收到了什么以及是使用那些数据测试或者诊断信息。Via报头域的值有特殊的作用,它扮演了请求链的跟踪者的俄角色。使用Max-Forwards报头域允许客户端限制请求链的长度,这对测试一个无限循环投送信息的代理链是很有用的。

如果请求是有效的,响应应该将全部的请求信息包含来实体主体中,并且有一个“message/http

Content-Type。此方法的响应不能被缓存。

 

 

9.9 CONNECT

 

规范预留了一个CONNECT方法名让代理动态的切换为一个隧道(如 SSL隧道)。

10 状态码定义Status Code Definitions

每个状态码都在下面进行了描述,包括其对应的方法和响应所需要的元信息。

10.1 消息1xx Informational 1xx

这个类别的状态码标识了一个临时的响应,只有状态行和自定义报头组成,由一个空行中止。此类别状态码没有必须的报头。因为HTTP/1.0没有定义1xx状态码,除非在实验情况下服务端不能发送1xx响应给HTTP/1.0客户端。

一个客户端必须准备在接受到正式的响应之前接受一个或多个1xx响应,即使客户端不期望一个100(继续)状态信息。未预期的1xx状态响应可以被用户代理忽略。

代理必须转递1xx响应,除非在客户端和客户端的连接被关闭,或者代理自身请求所产生的1xx响应。(例如:如果代理转递请求时添加一个“Expect:100-continue”域,那么它可以不必转递相应的100(继续)响应)。

10.1.1继续100 Continue

客户端应该继续这个请求。这个临时的响应用来通知客户端请求的最初部分已经接收到并且没有被服务拒绝。客户端应该通过继续发送剩余的请求,或者如果请求已经完成,则忽略此响应。服务端必须在请求完成后发送一个最终的响应。参看8.2.3对使用和处理此状态码的详细讨论。

10.1.2切换协议101 Switching Protocols

服务端理解并准备应答客户端的请求,通过Upgrade消息报头域来改变连接使用的程序协议。服务端会在发送完终止101响应的空行后立即切换为响应Upgrade报头域指定的协议。

协议应该在这样做有利的情况下进行切换。例如,切换为一个新的版本的HTTP协议比旧的协议有好处,而切换为一个实时的,同步的协议可能在处理使用此类功能的资源时更有利。

10.2 成功Successful 2xx

此类状态码标识客户端的请求被成功接收、理解并接受。

10.2.1 200 OK

请求已经成功。响应返回的信息取决于请求所用的方法。例如:

GET 响应返回一个对应于请求资源的实体。

HEAD 响应返回一对应于请求资源的实体报头域,没有消息主体。

POST 一个实体描述或保存动作的结果。

TRACE 一个包含服务接收的请求信息的实体。

10.2.2创建201 Created

请求被完成并导致新资源被创建。新创建的资源可以被返回响应实体中的URI引用,其中最准确的URI由Location报头域给出。响应应该包含一个含有资源特征列表的实体,用户或者用户代理可以从里面选择最合适的位置。实体格式由Content-Type报头域给出的媒体类型给出。源服务必须在返回201状态码之前返回响应。如果动作不能被立刻执行,服务端应该用202(接受)响应代替。

一个201响应可能含有一个ETag响应报头域标识请求变量创建的实体标记的当前值,参看14.19章。

10.2.3接受202 Accepted

请求已经被接受来处理,但处理还没有被完成。请求有可能会或者不会被遵行,因为它可能在处理过程中被拒绝。从一个异步操作中重发这样一个状态码是不容易的。

202响应是有意无委托的。它的目的是允许某些处理的请求(可能是一个批量处理会运行一天)不用要求用户代理到服务端的连接一直持续到处理完成。该响应的实体应该包含一个请求当前状态的标识,以及一个状态监控器的指示器或者一些用户可以判断请求何时被完成的估计。

10.2.4非权威信息203 Non-Authoritative Information

返回实体报头域中的元信息不是服务端用到的最终设置,但它是一个本地或者第三方拷贝推测出来的。这个设置可能是源版本的子集或者超集。例如,包含生成源服务知道的元信息超集的冠以资源的本地注释信息。这个代码的使用不是必需的,只是当响应会是200的时候才使用。

10.2.5无内容 204 No Content

服务已经完成请求但不需要返回一个实体主体,而可能需要返回更新元信息。响应的实体报头列表应该包含新的或者更新的元信息,这些信息应该与请求的变量相关。

如果客户端是一个用户代理,它不应该改变它的会导致请求发送的文档视图。这个响应是有意为允许动作的输入发生时不会导致用户代理的活动文档视图哥改变,虽然一些新的或者更新的元信息应该被应用到当期用户代理的活动视图的文档上。

204响应不能包含消息体,因此总是由报头域后的空行终止。

10.2.6重置内容205 Reset Content

服务端已经完成请求并且用户代理应该重置文档视图造成请求的发送。这个请求是有意允许动作的输入通过用户输入发生,跟着一个给出输入的清空列表,这样用户可以很容易的开始另一个输入动作。响应不能包含实体。

10.2.7局部内容 206 Partial Content

服务端完成资源的部分GET请求。请求必须包含一个Range报头域(14.35章)标识想要的范围,并且可以包含一个If-Range报头域(14.27章)来给出请求的条件。

响应必须包含以下报头域:

l         一个Content-Range报头域(14.16章)标识想拥有包含的范围,或者一个多部分/字节范围的Content-Type包含每一部分的Content-Range域。如果一个Content-Length报头域出现在响应中,它的值必须与消息体中传输的OCTET的实际数目相匹配。

l         Date

l         ETag 和(或)Content-Location,如果报头已经由200响应发送给同一个请求的话。

l         Expires, Cache-Control, 和/或Vary,如果域值可能不同于以前发送的响应里的同一变量。

如果206响应是一个使用强缓存校验的If-Range请求的结果,响应不应该包含其他的实体报头域。如果响应是一个使用弱校验的If-Range请求的结果,响应必须不能包含其它的实体报头域;这避免了缓存实体主体和更新的报头的矛盾。否则的话,响应必须包含所有的实体报头,那些已经同200响应返回给同一个请求的报头。

一个缓存必须不能将一个206响应和以前缓存的内容相结合,如果Etag或者Last-Modified报头没有完全匹配,参看13.5.4章。

不支持Range和Content-Range报头的缓存必须不能缓存206响应。

10.3 重定向Redirection 3xx

这个类别的状态码标识用户代理要做出进一步的动作来完成请求。要求的动作可以在不用与用户交互的情况下由用户代理发出,前提是当且仅当下一个请求使用的方法是GET或HEAD。客户端应该监测无限重定向循环,因为这样的循环会造成每个重定向的网络拥塞。

注意:规范的早期版本推荐了一个5次重定向的最大次数。开发者应该知道可能有实现了固定限制的客户端。

10.3.1多项选择300 Multiple Choices

请求资源对应于一组表示的任一个成员,每一个都有自己特定的位置,并且提供了代理驱动的协商信息,因此用户(或者用户代理)可以选择一个首选表示并重定向其请求到该位置。

除非是一个HEAD请求,响应应该包含有资源字符列表和位置的实体,由此客户或者客户代理可以选择最一个合适的。实体格式由报头域Content-Type给出的媒体类型指定。依托于格式和盈沪代理的能力,选择最合适的选项可以被自动执行。尽管如此,文档没有定义自动选择的标准。

如果服务有一个首选的表示选择,它应该在Location域里包含该表示的明确的URI;用户代理应该可以使用Location域值作为首选重定向。响应是可以缓存的,除非有其它的标识。

10.3.2永久移动301 Moved Permanently

请求资源被分配给一个新的永久性的URI,将来对此资源的引用都应该使用返回URI中的某一个。具有关联编辑能力的客户端应该在那些可能的地方自动重连到请求URI的引用,变更为由服务返回的一个或多个引用。响应是可缓存的,除非有其它的标识。

新的永久性的URI应该由响应中的Location域给出。除非请求方法是HEAD,响应的实体应该包含一个有执行新URI的超链接的简短的超文本注释。

如果在一个非GET或者HEAD请求的响应里接收到301状态码,用户代理必须不能自动重定向请求除非它可以被用户确认,因为这可能改变请求的初衷。

       注意:当在接收到一个301状态码后自动重定向一个POST请求时,一下已有的HTTP/1.0用户代理可能错误的将它改变为一个GET请求。

10.3.3 302 Found

请求资源临时性的放在一个不同的URI下。因为重定向有时会被更该,客户端应该在以后的请求中继续使用这个请求URI。响应只能在有Cache-Control或者Expires报头域标识时才能缓存。

临时性的URI应该由响应的Location域给出。除非请求方法是HEAD,响应的实体应该包含一个有新URL超链接的简短的超文本描述。

如果一个非GET或HEAD请求的响应里接收到302状态码,用户代理不能自动重定向请求,除非用户确认,因为这可能会改变请求的初衷。

注意:RFC1945和RFC2068规定不允许客户端改变重定向请求的方法。不过,绝大多数的用户代理实现将302作为303响应对待,在Location域值上执行一个GET方法而忽略原来的请求方法。状态码303和307已经添加给那些确定客户端所期望反作用种类的服务端。

10.3.4 303 See Other

请求的响应可以在不同的URI下找到并且应该应该使用一个GET方法来重新获取资源。这个方法出现的初衷是为了允许POST脚本来重定向用户代理选择资源。新URI不是源请求资源的替换引用。303响应不能被缓存,但第二次(重定向)请求的响应是可以缓存的。

这个不同的URI应该由响应的Location域给出。除非请求方法是HEAD,响应实体应该包含一个有指向新URI的超链接的简单超文本注释。

注意:很多HTTP/1.1前的用户代理不识别303状态。如果与这种客户端进行交互,应该使用302状态码代替,因为大多数用户代理对302的反应类似于这里描述的303。

10.3.5 304 Not Modified

如果客户端执行了一个有条件的GET请求并且访问被通过,但是文档并没有被修改,服务应该给出一个此状态码的响应。304响应不能包含一个消息体,因此在读取报头域后面的空行通常终止读入。

响应必须包含一下报头域:

l         Date,除非它的冗长是14.18.1章要求的。

如果一个无锁的源服务要求这些规则,并且代理和客户端添加自己的Date到一个没有该域的响应里,缓存应该做出合适的处理。

l         Etag和/或Content-Location,如果报头已经由200响应发送给同一个请求。

Expires, 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。响应只有在一个Cache-Control或者Expires报头域标识的时候才可以缓存。

临时的URI应该由响应的Location域给出。除非请求方法是HEAD,响应的实体应该含有一个指向新URI的超链接的简短超文本描述,因为很多HTTP/1.1以前的用户代理不识别307状态。所以,描述应该包含一个用户重发基于新URI的原始请求是所必须的信息。

如果307状态码响应对应的请求方法不是GET或者HEAD,用户代理不能自动重发请求除非经由用户同意,因为这可能会改变请求的初衷。

10.4 客户端错误Client Error 4xx

4xx类别的状态码是当客户端象是出错的时使用的。除了对HEAD请求的响应,服务端应该包含一个对错误情形进行解释的实体,不论它是一个临时的还是永久性的状况。这些状态码适用于任意请求方法。用户代理应该将包含的实体展示给用户。

如果客户端正在发送数据,使用TCP实现的服务端应该在关闭输入连接前,仔细确保客户端确认收到响应包含的包。如果客户端在关闭后继续向服务端发送数据,服务端的TCP栈将向客户端发送一个重置包,它将在客户端未确认的输入缓存被读取并在HTTP应用解析他们之前将其丢弃。

10.4.1失败的请求400 Bad Request

服务端由于请求语法错误不能理解请求。客户在做出修改前不应该重发请求。

10.4.2未授权401 Unauthorized

请求要求用户验证。响应必须包含一个WWW-Authenticate报头(14.47章)满足请求资源的提问能力。客户端可以重发有一个适配的Authorization的报头域的请求(14.8章)。如果请求里已经包含了认证证书,那么应该返回401响应来标识对于那些证书的认证被拒绝。如果401响应里包含了同上一个响应相同的提问,并且用户代理已经至少尝试了一次认证,那么它应该让用户知道响应所给出的实体,因为实体中可能包含相关的诊断信息。HTTP访问认证在"HTTP Authentication: Basic and Digest Access Authentication"【43】 中有所解释。

10.4.3必须付费402 Payment Required

此代码留作将来使用

10.4.4禁止403 Forbidden

客户端理解请求,但是拒绝完成它。认证不会有帮助,请求不应该被重发。如果请求犯法不是HEAD并且服务希望公布请求未被处理的原因,它应该在实体里描述被拒绝的原因。如果服务不希望客户端知道这个信息,它可以使用代码404(未发现)代替。

10.4.5未发现404 Not Found

服务没有找可匹配请求URI的资源。不标识状况是临时的还是永久的。如果服务端通过一些内部配置机制知道一个旧资源永久不可用并且没有推进的地址,它应该使用410(Gone)状态码。

这个状态码是在服务端不希望展现为什么服务被拒绝或者没有其他响应可用的时候使用。

10.4.6不允许的方法405 Method Not Allowed

请求URI指定的资源不接收请求队列指定的方法。响应必须包含一个Allow报头,给出一个请求资源的可用方法列表。

10.4.7不接受的406 Not Acceptable

请求指定的实体依照请求发送的接受报头只能生成内容特征不被接收的响应实体。除非是一个HEAD请求,响应应该给出一个含有可用实体特征列表的实体,以及用户或者用户代理可以选择的一个更恰当的位置。实体格式Content-Type报头域给定的媒体类型来指定。依靠格式和用户代理的能力,最合适的选择可能会自动完成。不过,此规范并没有定义自动选择的标准。

注意:HTTP/1.1服务端允许返回请求允许报头中不允许的响应。在有些情况中,这比返回406响应会更可取。我们鼓励用户代理检查响应中的报头来决定它是否可接收。

如果响应不能被接收,用户代理用该临时性停止接收更多的数据并询问客户决定下一步操作。

10.4.8需要代理认证407 Proxy Authentication Required

这个代码类似于401(未授权),不过它标识客户端首先要向代理认证它自身。代理必须返回一个Proxy-Authenticate报头域,它包含了用于代理对请求资源的提问能力。代理可以重发一个有适配Proxy-Authenticate报头域的请求(14.34章)。HTTP访问认证在“HTTP Authentication:

Basic and Digest Access Authentication” 有解释。

10.4.9请求超时408 Request Timeout

客户端没有在服务端所能等待的时间里产生请求。客户端可以稍后重发无须更改请求。

10.4.10冲突 409 Conflict

由于资源的当前状态有冲突导致请求未能完成。这个代码只有在预期客户端有能力解决冲突并重新提交请求的情况下使用。响应体应该包含足够的信息来让客户认识冲突的资源。理想情况下,响应实体应该包哈足够的信息让客户或者客户代理定位问题;不过,那样可能不现实也不是必需的。

冲突最可能发生在对PUT请求的响应里。例如,如果使用了版本控制并且PUT的实体包含了对某个资源的变更,而这又跟早一点(第三方)的请求所产生的相冲突,服务端可以使用409响应来标识出它不能完成请求。这种情况下,响应实体最好包含一个两个版本的差异的列表,其格式由响应的Content-Type来定义。

10.4.11失效410 Gone

请求资源不再可用并且没有推进的地址。这种情况被认为是永久性的。有链接编辑功能的客户端应该在征得用户同意后删除该请求URI的引用。如果服务端不知道,或者没有能力决定,无聊状况是否是永久性的,应该使用404(未发现)代替。响应是可缓存的除非有其他标识。

410响应主要用来通过通知接收者资源有意地无法获取并且服务拥有者要去删除资源的远程链接辅助web维护工作。这个事件通常在限制时间,增值服务以及个人所属资源不再在服务端站点工作时发生。没有必要标记所有的永久性不可用资源为“gone”或者将标记保持一段时间——那是留给服务端拥有者去决定的。

10.4.12需要长度411 Length Required

服务端拒绝一个没有定义Content-Length的请求。客户端可以重发请求,如果它增加了一个Content-Length报头域来存放请求信息的消息主体的长度。

10.4.13预处理失败412 Precondition Failed

测试服务器时一个或多个请求报头域给出的预处理评估为错误的。这个响应代码欲寻客户端在当前资源元信息(报头域值)放置前提,并由此防止请求方法被用到非客户端想要的资源上。

10.4.14 413 Request Entity Too Large

服务决绝处理一个请求,原因是请求实体超过服务端想要或者能够处理的大小。服务端可能会关闭与客户端的连接来方式客户端继续请求。如果是临时的情况,服务端应该包含一个Retry-Afte报头域来标识它是临时的,客户端可以等一会重试。

10.4.15请求URI过长414 Request-URI Too Long

服务拒绝应答请求,因为请求URI的长度长处服务能解释的范围。这种少见的情况往往发生在客户端错误将一个POST请求转换为有很长查询信息的GET请求、客户端掉进一个重定向URI黑洞(如重定向URI的前缀指向了自己的后缀)或者服务受到尝试探测出现在那些使用固定长度缓存来读取或者处理请求URI的服务端的安全漏洞的客户端的攻击。

10.4.16不支持的媒体类型 415 Unsupported Media Type

服务端拒绝请求,原因是请求的实体使用了请求方法请求的资源无法支持的格式。

10.4.17请求范围不满足416 Requested Range Not Satisfiable

当一个请求包含一个Range请求报头域,并且该域没有范围指定值与当选中资源的当前范围重叠,而请求又没有包含If-Range请求报头域时,服务端应该返回这个状态代码的响应。(byte-ranges以为折所有字节范围指定值的第一个字节位置要大于选中资源的当前长度)。

当这个状态码是返回给byte-range请求时,响应应该包含一个Content-Range实体报头域来指出所选资源的当前长度(参看14.16章)。这个响应不能使用multipart/byteranges内容类型。

 

10.4.18期望失败 417 Expectation Failed

Expect请求报头域给出的期望不能被服务满足,或者服务有确凿的证据表明请求不能被下一个服务满足。

10.5 服务器错误Server Error 5xx

响应状态码以5开头表示服务器知道自己出错或者没有能力执行请求。除响应HEAD请求外,服务应该包含一个实体,实体给出错误形式的解释,以及是一个临时还是永久的状况。用户代理应该展示给用户所包含的实体。这些响应码适用于任何请求方法。

10.5.1服务器内部错误500 Internal Server Error

服务器遇到意外情况,致使无法完成请求。

10.5.2未实现501 Not Implemented

服务器不支持要完成请求的所需要的功能。这是当服务器不能识别请求方法和没有能力支持方法所需要的资源时恰当的响应。

10.5.3坏的网关502 Bad Gateway

当服务但当一个网关或者代理的角色,尝试实现请求时从访问的上游服务器接收到一个无效的响应。

10.5.4服务不可用503 Service Unavailable

由于暂时过载或者服务端维护导致当前服务不能处理请求。这意味着只是一个暂时的状况,稍后会得到环节。如果知道,延迟的长度可以用一个Retry-Afte报头标识。如果没有给出Retry-After,客户端应该自行处理此响应。

注意:503状态码的存在并不是强制服务端在过载时使用它。某些服务可能希望简单的拒绝连接。

10.5.5网关超时504 Gateway Timeout

作为一个网关或代理的服务端,没有从URI(如HTTP, FTP, LDAP)指定的上游服务器或者它要完成请求所需要访问的辅助服务器(例如 DNS)那儿接收到及时的响应。

注意:实现者应该注意:一些已有的代理在DNS查找超时时会返回400或者500。

10.5.6不支持的HTTP版本505 HTTP Version Not Supported

服务器不支持或者拒绝支持请求里所有的HTTP协议版本。服务器指出不能或者不想使用与客户端相同的主版本来完成请求,如3.1章所描述,而不是返回错误信息。响应应该包含一个实体来描述为什么版本不被支持以及服务器所支持的其他协议。

 

0 0
原创粉丝点击