5 请求
一个从client到server的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请求行
以一个方法标记开始,跟着URI,和版本协议,以CRLF结束。SP分隔。除了在最后的CRLF不能有CR,LF。
Request-Line = Method SP Request-URI SP HTTP-Version CRLF
5.1.1方法
方法标记表示将会用在请求资源上的方法,是大小写敏感的。
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头区给出。Response的返回代码总是告诉client一个方法可否应用到一个资源,因为总是在变。一个server应该返回405如果方法可以识别但不能用于请求资源,返回501如果方法不可识别或没有被origin server实现。方法get和head必须被所有的通用目的的server实现。所有其他方法是可选的;但是,如果上面的方法被实现,他们必须具备sec9定义的语义。
5.1.2URI
是一个统一资源标记(3。2)标记了request请求的资源。
Request-URI = "*" | absoluteURI | abs_path | authority
4个选项取决于request的性质。星号意思是request并不指定某一特定资源,而是server本身,只在方法并不一定针对资源时。一个例子:
OPTIONS * HTTP/1.1
如果请求是发给一个代理,absoluteURI形式是必须的。代理被请求来传递request或从一个有效缓存中服务,返回response。注意代理可以传递这个request给另外一个代理或直接给被absoluteURI指定的server。为了避免request循环,一个代理必须能够识别所有它的server名,包括别名,局部变量,和IP地址。里:
GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
为了允许传递所有的未来的HTTP版本中的request,所有的HTTP/1。1server必须接收request的absoluteURI,即使HTTP/1。1client只产生他们用来代理。
Authority形式只被CONNECT方法使用。(sec9.9)
最通用的URI形式是用来标记在一个origin server或gateway上的资源。在这种情况下,URI的绝对路径(abs_path)必须作为URI被传递,而且URI的网络路径(authority)也必须被作为一个Host头区被传递。例如,一个希望直接从origin server得到上面指定资源的request会创建一个到“www.w3.org”80端口的TCP连接并且发送这一行:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
跟着的是request的其他剩余部分。注意绝对路径不能是空的;如果确实没有,必须作为“/”给出。
URI以SEC3。2。1给出的格式传送。如果URI使用”%HEX HEX”编码[42]的形式编码,origin server必须解码URI一合适的解释request。Server应该对无效的URI给出合适的状态码返回。
一个transparent proxy当把request传递给内部server时绝对不能重写接收到的URI的“abs_path”部分,除非把null abs_path用“/”替换。
注意:“no rewrite”阻止了proxy改变request的原本意义,当origin server使用非保留URI字符对应保留目的时。实现者应该意识到一些HTTP/1。1前proxy可能重写uri。
5.2 Request标记的资源
被一个request请求的资源由uri和host头区精确确定。
当决定一个HTTP/1/1request请求的资源时,一个origin server如果不允许使用host来区别资源,那么可以忽略host头区。(sec19.6.1)
而一个确实使用host(又叫虚拟主机)区分资源的origin server使用下面原则处理HTTP/1。1request请求的资源:
1.如果URI是absoluteURI,那么主机名是其中一部分,任何其他主机名头区被忽略。
2.如果URI不是,并且包含HOST头区,那么host被头区决定。
3.400反馈1,2无效的。
HTTP/1。0是没有HOST头区的,可以使用直观推测方法来决定请求的精确资源。
5.3请求头区
头区允许client传递额外的关于request和client的自身信息给server。这些区就算request的描述符,就象程序语言的参数一样。
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
s头区的名字可以跟随一个改变的版本号而被扩展。但是,新的或实验的头区可以被给通用头区的语义如果通讯双方都认同。认不出的头区被认为是实体头区。
6 Response
当接收和解析一个request message后,一个server用一个HTTPresponse messge返回。
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状态行
一个response message的第一行是状态行,由协议版本,跟状态码,跟对应文本段,每一个用SP分隔。没有CR或LF被允许除了最后的CRLF。
Status-Line = HTTP-Version SP Status-Code SP Reason-Phrase CRLF
6.1.1状态码和原因段
状态码是一个3数字位结果编码,去理解和满足请求。Sec10完全定义。原因段是给一个简短的文本描述给status-code。状态码是自动使用而原因段是人工使用。Client并不需要去检查和表示原因段。
第一位定义了response的分类。后2位没有分类的意思。第一位有5个值。
· 1xx: request收到,继续处理
· 2xx: action被成功接收,理解,接受
· 3xx:还有其他action要做
· 4xx: request有问题
· 5xx: server有问题不能解决有效request的请求。
下面是定义的值和推荐原因段,当然可以自己定义。
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应用并没有被要求去理解他们但很明显是需要的。但是,应用必须理解代码的分类,也就是第一位,并且对任何不认识的response等同于对应类别的x00,但是不缓存它。例如,如果一个431被client接收到但不识别,它可以认为它的request本身并没有错,并且把response作为400处理。在这种情况下,user agent应该给user展现response返回的整个entity,因为entity可能包含人可以识别的信息来解释不寻常的状态。
6.2 Response 头区
用来让server放在status-line中不能放的关于response的额外信息。这些头区给出了server的信息和更深入的关于REQUEST-URI指定的资源进入。
response-header = Accept-Ranges ; Section 14.5
| Age ; Section 14.6
| 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
s头区的名字可以跟随一个改变的版本号而被扩展。但是,新的或实验的头区可以被给通用头区的语义如果通讯双方都认同。认不出的头区被认为是实体头区。
7 Entity
request和response可以传递一个实体如果request方法和response状态码未加限制的话。一个entity由头区和体组成,虽然一些response只包含头区。
在这个段中,发送者和接收者可以是client或server,看谁发送和接收实体。
7.1实体头区
定义了实体的描述数据,如果没有实体,那就是request指定资源的描述数据。一些是可选的,一些是必须的。
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
扩展头区机制允许额外的头区定义而不用改变协议,但是这些区并不能假定会被接收者识别出。没有识别的要被接收者忽略而且必须被透明proxy传递。
7.2 Entity Body
它是以实体头区定义的形式和编码形成的伴随request和response发送的。
entity-body = *OCTET
一个Entity Body只存在于一个存在消息体的消息中,(sec4.3)。通过解码传输编码从message-body中得到entity-body。
7.2.1类别
当一个entity-body被一个消息包含时,通过头区Content-Type和Content-Encoding决定类型。这些定义了一个两层的 有序的编码模型。
entity-body := Content-Encoding( Content-Type( data ) )
Content-Type声明了数据的类型。Content-Encoding用来给出额外的内容编码,通常是用来数据压缩的,是被request资源的属性。没有默认的编码。
任何包含一个实体的HTTP/1。1消息应该包含一个Content-Type头区来定义那个体的media type。如果media type没有在一个content-type区被给出,接收着可以通过内容或uri的名字扩展来猜。如果还是未知,那就应该作为“application/octetstream”。
7.2.2 实体长度
即使消息体被任何传输编码应用前的长度。Sec4.4定义了怎么确定一个消息体的传输长度。
8 连接
8.1持久连接
8.1.1目的
持久连接之前,一个单独的TCP连接需要每次取得URL来建立,增大了HTTP server的负载并且引起internet的拥挤。使用联机图片和其他相关数据资源通常要求一个client在极短时间向相同的server发送多个request。关于这些性能问题的分析和对一个实验性实现的结果是可用的[26][30]。实现经验和实际的HTTP/1。1(RFC2068)的测量显示了很好的结果。也产生了可选的代替,例如,T/TCP[27]。
持久的HTTP连接有很多优点:
l 打开和关闭更少的TCP连接,节省了通讯链路上路由器和主机(clients,servers,proxies,gateways,tunnels,或caches)上的CPU消耗,也节省了主机上对TCP控制块的内存消耗
l HTTP连接和请求可以在一次连接上pipeline。这允许一个client发送多个request而不用等response,允许单个TCP连接被更有效地使用而节省了大量时间。
l 网络拥塞被降低了,因为减少了TCP打开的PACKETS,和允许TCP有更多的时间决定网络拥挤状态
l 等待下一个request时间被降低了,应为可以花费更少的时间在TCP握手上
l HTTP可以更好地发展,因为错误在不关闭TCP连接的情况下被报告。HTTP的未来版本的client可以乐观地使用一个新特征,但是要和一个旧server通讯就要在错误被报告时尝试旧语义。
HTTP应用应该实现持久连接。
8.1.2整体流程
HTTP/1。1和其他早期HTTP的重要区别就是持久化连接是所有HTTP连接的默认连接。也就是,除非有另外指明,client应该假定server保持一个持久连接,即使server发送一个error。
持久化连接提供了一个机制,通过它一个client和一个server能够表示tcp连接的关闭,就是使用connection 头区。一旦一个close被标记,client不能在connection上发送任何request。
8.1.2.1 Negotiation
一个HTTP/1。1server可以假定一个HTTP/1。1client想要保持一个持久化连接直到一个connection区被指定为“close”,并且被以request发送。如果server想在response之后关闭连接,它应该这样指明。
一个HTTP/1。1client可以期待连接保持,但是通过response的connection头区来决定是否保持;而如果不想连接保持,就应该发一个close的connection头区。
如果client和server有一个发了,那么request是连接的最后一个。
Client和server不应该假定低于HTTP1。1的版本会维持一个持久化连接。Sec19.6.2提供更多兼容信息。
为了保持持久,所有在连接中的消息必须有一个自定义的消息长度,sec4.4。
8.1.2.2流水线
一个支持持久化连接的client可以流水它的request(也就是说,发送多个request而不必等待response)。一个server必须发送它的response给那些request按request应该接收到的顺序。
Client在连接建立后马上假定持久化连接和流水线存在的如果第一次流水线试图失败要准备重新建立连接。如果一个client做这样的重试,它在知道连接是持久化之前绝对不能pipeline。如果server在发送所有对应response之前关闭连接,client也必须要准备重发所有的请求。
Client不应该发送非等幂(或序列)方法的request。否则一个运输连接的过早终结可能会导致结果的不确定。一个希望发送一个非等幂request的client应该等到前一个request对应的response到了后再发。
8.1.3代理服务器
proxy正确实现connection头区(sec14.10)的属性是非常重要的。
Proxy必须分别给它的client和origin server(或其他proxy server)标记持久化连接。每一个持久化连接对应一个链。
一个proxy绝对不能建立HTTP/1。1持久连接和一个HTTP/1。0client(RFC2068)。
8.1.4实践考虑
server通常有一些超时值,超过了这些值就不会维持一个活动连接。Proxy可以设得更高因为可能一个client可能会和它r做更多的连接。这个值本身的大小没有限制。
当一个client或server想要超时,它应该给那个连接发一个优美的中断。Client和server都应该经常地观察传输的另一端,合适地给以处理。如果相反的话会导致网络资源耗尽。
一个client,server或proxy可以在任何时候关闭传输连接。例如,一个client会开始发送一个新的request同时一个server决定关闭这个看似空闲的连接。从server的角度看,连接就要被关闭,从client的角度看,一个request正在被发送。
这意味着client ,server,proxy必须能够从异步关闭事件中恢复。Client软件应该从新打开连接从新发送失败的request,只要request序列是等幂的(sec9.1.2)就不需要用户交互。不等幂的方法或序列绝对不能被自动重发,虽然user agent可以提供一个手工操作来选择重新发送。User-agent软件的确认回代替用户的确认。如果第2次请求序列失败自动重发不应该继续。
Server应该总是对一个连接至少发一个response,如果可能的话。Server不应该在发送一个response的过程中关闭一个连接,除非预测到一个网络连接或client失败。
使用持久连接的client应该限制他们维持到同一个server的并行连接数。一个单个的user client不应该对任何server或proxy保持对于2个连接。一个proxy应该使用最多2*N个连接到另一个server或proxy,N是同时活跃的users个数。这些原则被用来提高http response时间并且避免拥塞。
8.2消息传送要求
8.2.1持久连接和流控制
HTTP/1.1的server应该保持持久连接并且使用TCP的流控制机制来解决临时过载的问题,而不是知道client会retry还终止连接。后者会加重网络租塞。
8.2.2 监视连接中的错误状态信息
一个HTTP/1。1(或之后的)正在发送消息体的 client当它正在传递request时应该监视网络连接的错误状态。如果client看到一个错误状态,它应该迅速终止消息体的发送。如果正在用“chunked”(sec3.6)编码发送,一个0长度的chunk和空尾部可以被使用用来标志消息的结束。如果消息体先于一个Content-Length头部,client必须关闭连接。
8.2.3使用100status
100状态的存在是为了允许一个正在发送带body的request message的client来决定是否一个origin server想要接收request(基于request header),这发生在实际发送request body之前。在某些情况下,发送一个不被server看就拒绝的消息体是不合适和浪费效率的。
对HTTP/1。1client的要求:
。如果一个client愿意在发送一个request body前等待100response,它必须发送一个期待100的头区。
。一个client决不能发送一个期待100的头区如果它不想发request body。
由于更老板本的存在,协议允许一个client发了期待100头区后没有受到417,100。因此,一个client发了期待100头区后就不应该无限等待request。
对HTTP/1。1server的要求:
l 当接收到一个包含expect “100-continue”头区的request时,origin server必须要么一100(Continue)状态返回并且继续从输入流中读,要么返回一个终止状态编码。Origin server 绝对不能在发送100response之前等待request body。如果它返回一个终止状态,它可以关闭连接或可以继续读但放弃request的剩余部分。它决不能执行request的方法如果它返回一个终止符。
l 一个origin server不应该发送一个100(continue)response,如果request 消息没有包含expect “100-continue”头区,并且也绝对不能发送这样的response如果request是来自一个HTTP/1。0(或更早版本的)client。有一个意外:为了和RFC2068兼容,一个server可以发送一个100状态在response中给一个HTTP/1。1put或post request,尽管没有包含expect “100-continue”头区。这个异常,只适用于HTTP/1。1request,并不适用于其他HTTP版本,目的就是减少client的等待时间。
l 一个origin server可以可以忽略100如果它已经接收到一些或全部的request body.
l 一个发送了一个100的origin server必须在收完body并且处理后发送一个final status code,除非它过早地终止连接。
l 如果一个origin server接收到一个未包含Expect 100头区的request,而又包含一个body,server在从连接读整个body前回以一个final status,那么server不应该关闭连接直到它读了整个request或直到client关闭了连接。否则,client不能可靠地接收response。然而,这个要求并不是说保护server免受服务拒绝攻击或错误的client实现。
对HTTP/1。1proxy的要求:
。如果一个代理接收到一个包含100期待的头区的request,代理要么知道要么不知道下一个server对HTTP1。1的兼容,它必须转发request,包括expect头区。
。如果proxy知道下一个server 支持http/1.0或更低,它决不能转发,而必须发挥417。
。Proxy应该维护一个关于最近接收的下一个server的HTTP版本号的缓存。
。一个proxy决不能返回100response给一个HTTP/1。0的client(不包含100-continue期待)。这个请求覆盖了转发1xx response的规则。
8.2.4 client在server过早关闭连接后的行为
如果一个HTTP/1。1client发送一个包含body的request,但是没有包含100头区期待,而且并不是直接连HTTP/1。1origin server,而且看到了从server过来的连接关闭,应该重试request。如果重试,它可以采用下面的2等幂算法来确保得到可靠连接:
1. 初始化一个到server的新连接
2. 发送request-headers
3. 初始化一个R,来存放到server 的来回是,如果不可得就设置成5s。
4. 计算T=R*(2**N),N是之前尝试重发的次数。
5. 等一个错误response或Ts
6. 如果没有接收到error response,Ts后发送request的body。
7. Client看到连接被过早关闭,重复1步直到request被接收,或收到一个错误response,或client不耐烦关闭了尝试进程。
在任何错误状态被接收的点,client
l 不应该继续
l 应该关闭连接如果还没有完成发送request message