zoukankan      html  css  js  c++  java
  • HTTP的RFC解析

            RFC(Request For Comments)-意即“请求评议”。HTTP(超文本传输协议)是运行于应用层的协议,基于TCP协议而运作,描述的是发送方与接收方的通信协议。它适应了分布式超媒体协作系统对灵活性及速度的要求。它是一个一般的、无状态的、基于对象的协议,通过对其请求方法(request methods)进行扩展,可以被用于多种用途,比如命名服务器(name server)及分布式对象管理系统。HTTP的一个特性是数据表现形式是可以定义和协商的,这就允许系统能独立于数据传输被构建。

           术语(表示HTTP通信中各参与者和对象扮演的不同角色):

            连接(connection)  两个应用程序以通讯为目的在传输层建立虚拟电路。

            消息(message)   HTTP通讯的基本单元,在连接中传输的结构化的、有顺序的字节

             请求(request)   HTTP的请求消息

             回应(response)  HTTP的回应消息

             资源(resource)   网络上可以用URI来标识的数据对象或服务

             实体(entity)可被附在请求或回应消息中的特殊的表示法、数据资源的表示、服务资源的回应等,由实体标题(entity header)或实体主体(entity body)内容形式存在的元信息组成。

             客户端(client)指以发出请求为目的而建立连接的应用程序。

             用户代理(user agent)指初始化请求的客户端,如浏览器、编辑器、蜘蛛(web爬行机器人)或其它终端用户工具。

             服务器(server)   指接受连接,并通过发送回应来响应服务请求的应用程序。

             原始服务器(origin server)   存放资源或产生资源的服务器。

             代理(proxy) 同时扮演服务器及客户端角色的中间程序,用来为其它客户产生请求。请求经过变换,被传递到最终的目的服务器,在代理程序内部,请求或被处理,或被传递。代理必须在消息转发前对   消息进行解释,而且如有必要还得重写消息。代理通常被用作经过防火墙的客户端出口,用以辅助处理用户代理所没实现的请求。

              网关(gateway)   服务器之间的服务器。与代理不同,网关接受请求就好象它就是被请求资源所在的原始服务器,发出请求的客户端可能并没有意识到它在与网关进行通讯。网关是网络防火墙服务器端的    门户。对非HTTP系统资源进行访问时,网关做为中间的协议翻译者。

              隧道(tunnel)    隧道就好象连接两端看不见的中继器。处于激活状态时,它虽然是由HTTP请求来初始化的,但它并不参与HTTP通讯。当需要中继连接的两端关闭后,隧道也自然终止。在入口有需求及 中间程序无法或不该解释要中继的通讯时,通常要用到隧道技术。

               缓存(cache)  指程序本地存储的回应消息和用来控制消息存储、重获、删除的子系统。缓存回应的目的是为减少请求回应时间,以及未来一段时间对网络带宽的消耗。任何客户端及服务端都可以包含缓 存。服务器在以隧道方式工作时不能使用缓存。

              任何指定的程序都有能力同时做为客户端和服务器。我们在使用这个概念时,不是看程序功能上是否能实现客户及服务器,而是看程序在特定连接时段上扮演何种角色(客户或服务器)。同样,任何服务器可以扮演原始服务器、代理、网关、隧道等角色,行为的切换取决于每次请求的内容。

              概述(Overall Operation)

              HTTP协议是基于请求/回应机制的。客户端与服务器端建立连接后,以请求方法、URI、协议版本等方式向服务器端发出请求,该请求可跟随包含请求修饰符、客户信息、及可能的请求体(body)内容 的MIME类型消息。服务器端通过状态队列(status line)来回应,内容包括消息的协议版本、成功或错误代码,也跟随着包含服务器信息、实体元信息及实体内容的MIME类型消息。绝大多数HTTP通讯由用户代理进行初始化,并通过它来组装请求以获取存储在一些原始服务器上的资源。在最简单的情况下,通过用户代理(UA)与原始服务器(O)之间一个简单的连接(v)就可以完成。

              request chain ------------------------>

           UA -------------------v------------------- O          <----------------------- response chain

     更复杂的情况是当请求/回应链之间存在一个或更多中间环节。总体看来,有三种中间环节:代理(proxy)、网关(gateway)、隧道(tunnel)。代理(proxy)是向前推送的代理人(agent),它以绝对形式接收URI请求,重写全部或部分消息,并将经过改写的请求继续向URI中指定的服务器处推送。网关是接收代理,它处于服务器层之上,在必要时候,它用服务器可识别的协议来传递请求。隧道不改变消息,它只是连接两端的中继点。在有中间层(如防火墙)或中间层无法解析消息内容的情况下,需要靠隧道技术来帮助通讯穿越中间层。

               request chain -------------------------------------->

           UA -----v----- A -----v----- B -----v----- C -----v----- O

               <------------------------------------- response chain

    上面的图形表示在用户代理和原始服务器之间有三个中间层(A,B和C)。由图可见,请求或回应消息在整个信息链上运行需要通过四个单独的连接,它与在此之前介绍的简单情况是有区别的,而且此区别是十分重要的。因为HTTP通讯选项可以设置成几种情况,如只最近的非隧道邻居连接、只与信息链末端连接、或者可与链中全部环节连接等等。虽然上面的图是线性的,而实际上每个参与环节都在同时与多方进行通讯活动。例如,B在接受除A之外其它客户端请求的同时,向除C之外的其它服务器推送请求,在这个时刻,它可能接受到A的请求,并给予处理。参与通讯的任何一方如果没有以隧道方式进行工作,必须要借助内部缓存机制来处理请求,如果链上某个参与方碰巧缓存了某个请求的回应,那就相应于缩短了请求/回应链。下面的图例演示了当B缓存了从O经由C过来的回应信息,而UA和A没缓存的情况:

     
              request chain ---------->
           UA -----v----- A -----v----- B - - - - - - C - - - - - - O
              <--------- response chain
     并非所有的回应都可以被缓存,某些请求所包含的修饰符中可能对缓存行为进行了特定指明。一些基于HTTP/1.0的应用使用了启发式的方法来描述哪些回应可被缓存,而哪些则不可以,但遗憾的是,这些规则并没有形成标准。在Internet上,HTTP通讯往往基于TCP/IP的连接方式。缺省的端口是TCP 80[15]口,但也可以使用其它端口。并不排除基于Ineternet上的其它协议或网络协议的HTTP实现方式,HTTP只是假定传输是可靠的,因而任何能提供这种保证的协议都可以被使用。至于HTTP/1.0请求和回应在数据传输过程中的数据结构问题,不在本文讨论范围之内。实验室应用除外,当前的做法是客户端在每次请求之前建立连接,而服务器端在发送回应后关闭此连接。不管客户端还是服务器端都应注意处理突发的连接中断,因为双方都有可能因为用户操作、自动超时、程序失败等原因关闭与对方的连接。

    补充反馈方式(augmentedBNF)包括下面的结构:

           要解释的名词=名词解释(name = definition)规则的名字(name)就是它本身(不带任何尖括号,“<”,“>”),后面跟个等号=,然后就是该规则的定义。如果规则需要用多个行来描述,利用空格进行缩进格式排版。某些基本的规则使用大写,如SP, LWS, HT, CRLF, DIGIT, ALPHA,等等。定义中还可以使用尖括号来帮助理解规则名的使用。面意思("literal")文字的字面意思放在引号中间,除非特别指定,该段文字是大小写敏感的。

           规则1|规则2(rule1 | rule2)

          “|”表示其分隔的元素是可选的,比如,“是|否”要选择‘是’或‘否’。

        (规则1 规则2)((rule1 rule2))

          在圆括号中的元素表明必选其一。如(元素1(元素2|元素3)元素4)可表明两种意思,即“元素1 元素2 元素4”和“元素1 元素3 元素4”*规则(*rule)在元素前加星号“*”表示循环,其完整形式是“<n>*<m>元素”,表明元素最少产生<n>次,最多<m>次。缺省值是0到无限,例如,“1*元素”意思是至少有一个,而“1*2元素”表明允许有1个或2个。

           [规则]([rule])     方括号内是可选元素。如“[元素1 元素2]”与“*1(元素1 元素2)”是一回事。

            N 规则(N rule)

           表明循环的次数:“<n>(元素)”就是“<n>*<n>(元素)”,也就是精确指出<n>取值。因而,2DIGIT 就是2位数字, 3ALPHA 就是由三个字母组成字符串。#规则(#rule)

          “#”与“*”类似,用于定义元素列表。完整形式是“<n>#<m>元素”表示至少有<n>个至多有<m>个元素,中间用“,”或任意数量的空格(LWS-linear whitespace)来分隔,这将使列表非常方便,如“(*LWS元素 *( *LWS "," *LWS 元素 ))”就等同于“1#元素”。空元素在结构中可被任意使用,但不参与元素个数的计数。也就是说,“(元素1),,(元素2)”仅表示2个元素。但在结构中,应至少有一个非空的元素存在。缺省值是0到无限,即“#(元素)”表示可取任何数值,包括0;而“1#元素”表示至少有1个;而“1#2元素”表示有1个或2个。

    ;注释(; comment)

         分号后面是注释,仅在单行使用。隐含*LWS(implied *LWS)

             本文的语法描述是基于单词的。除非另有指定,线性空格(LWS)可以两个邻近符号或分隔符(tspecials)之间任意使用,而不会对整句的意思造成影响。在两个符号之间必须有至少一个分隔符,因为它们也要做为单独的符号来解释。实际上,应用程序在产生HTTP结构时,应当试图遵照“通常方式”,因为现在的确有些实现方式在通常方式下无法正常工作。

             

    消息类型(Message Types)
     
     HTTP消息由客户端到服务器的请求和由服务器到客户端的回应组成。
    HTTP-message   = Simple-Request   ; HTTP/0.9 messages
                          | Simple-Response
                          | Full-Request    ; HTTP/1.0 messages
                          | Full-Response
     完整的请求(Full-Request)和完整的回应(Full-Response)都使用RFC822[7]中实体传
    输部分规定的消息格式。两者的消息都可能包括标题域(headers,可选)、实体主体(entity
    body)。实体主体与标题间通过空行来分隔(即CRLF前没有内容的行)。
    Full-Request  = Request-Line   ; Section 5.1
                            *( General-Header  ; Section 4.3
                             | Request-Header  ; Section 5.2
                             | Entity-Header )  ; Section 7.1
                            CRLF
                            [ Entity-Body ]   ; Section 7.2
    Full-Response   = Status-Line    ; Section 6.1
                            *( General-Header   ; Section 4.3
                             | Response-Header  ; Section 6.2
    | Entity-Header )   ; Section 7.1
                            CRLF
                            [ Entity-Body ]   ; Section 7.2
     
     简单请求(Simple_Request)与简单回应(Simple-Response)不允许使用任何标题信息,
    并限制只能使用唯一的请求方法(GET)
           Simple-Request  = "GET" SP Request-URI CRLF
           Simple-Response = [ Entity-Body ]
     不提倡使用简单方式请求格式,因为它防止了服务器在接到简单请求时对返回实体的介
    质类型进行验证。

    消息标题(Message Headers)


     HTTP标题域,包括主标题(General-Header,4.3节)、请求标题(Request-Header ,5.2节)、
    回应标题(Response-Header ,6.2节)及实体标题(Entity-Header,7.1节),都遵照RFC822-3.1
    节[7]给出的通用格式定义。每个标题域由后紧跟冒号的名字,单空格(SP),字符及域值组
    成。域名是大小写敏感的。虽然不提倡,标题域还是可以扩展成多行使用,只要这些行以一
    个以上的SP或HT开头就行。
    HTTP-header  = field-name ":" [ field-value ] CRLF
    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, tspecials, and quoted-string>
    标题域接收的顺序并不重要,但良好的习惯是,先发送主标题,然后是请求标题或回应
    标题,最后是实体标题。
     当且仅当标题域的全部域值都用逗号分隔的列表示时(即,#(值)),多个有相同域名
    的HTTP标题域才可以表示在一个消息里。而且必须能在不改变消息语法的前提下,将并发
    的域值加到第一个值后面,之间用逗号分隔,最终能将多个标题域结合成“域名:域值”对。

    请求URI(Request-URI)
     
     请求URI就是统一资源标识符(3.2节),用来标识要请求的资源。
    Request-URI  = absoluteURI | abs_path
     上面两种请求URI方式可根据实际的请求方式选择使用。
     绝对URI(absoluteURI)格式只在代理(proxy)在产生请求时使用。代理的责任是将
    请求向前推送,并将回应返回。如果请求是GET或HEAD方式,而且之前的回应被缓存,
    如果代理忽略标题域的过期信息限制,它可能使用缓存中的消息。注意,代理可能将请求推
    送至另外一个代理,也可将请求直接送至绝对URI中所指定的目的服务器。为了避免请求
    循环,代理必须能够识别它的所有服务器名,包括别名、本地变量及数字形式的IP地址。
    下面是一个请求队列的例子:
    GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.0
     最普通的请求URI形式就是原始服务器或网关用来标识资源的方式。在这种方式下,
    只有给出绝对路径的URI才能被传输(见3.2.1节)。例如,如客户端希望直接从原始服务
    器上接收资源,它们将产生一个与主机"www.w3.org"80端口的TCP连接,并在完整请求之
    后发送下面的命令:
    GET /pub/WWW/TheProject.html HTTP/1.0
     注意绝对路径不可以为空,如果URI中没有内容,也必须加上一个"/"(server root)。
     
     请求URI以编码字符串方式传输,有些字符可能在传输过程中被转义(escape),如变
    成“%HEXHEX”形式。具体这方面内容请参见RFC1738[4]。原始服务器在正确解释请求
    之前必须对请求URI进行解码。

    请求标题域(Request Header Fields)


     请求标题域允许客户端向服务器端传递该请求的附加信息及客户端信息。该域做为请求
    的修饰部分,遵照编程语言程序调用参数的语法形式。
    Request-Header = Authorization   ; Section 10.2
                          | From    ; Section 10.8
                          | If-Modified-Since  ; Section 10.9
                          | Referer    ; Section 10.13
                          | User-Agent   ; Section 10.15
     请求标题域名只有在与协议版本的变化结合起来后,才能进行可靠的扩展。实际上,新
    的或实验中的标题域只要能被通讯各方识别,其语法就可使用,而无法识别的标题域都将被
    视为实体域。

     回应(Response)


     在接收、解释请求消息后,服务器端返回HTTP回应消息。
    Response   = Simple-Response | Full-Response
    Simple-Response  = [ Entity-Body ]
    Full-Response  = Status-Line    ; Section 6.1
                             *( General-Header   ; Section 4.3
                              | Response-Header  ; Section 6.2
                              | Entity-Header )   ; Section 7.1
                             CRLF
                             [ Entity-Body ]   ; Section 7.2
     
     当请求是HTTP/0.9的或者服务器端只支持HTTP/0.9时,只能以Simple-Response方式
    回应。如果客户端发送HTTP/1.0完整请求后,接收到的回应不是以状态行(Status-Line)
    开头的,客户端将其视为简单回应,并相应对其进行分析。注意,简单请求只包括实体主体,
    它在服务器端关闭连接时终止。

    状态代码和原因分析(Status Code and ReasonPhrase)

     状态代码(Status-Code)由3位数字组成,表示请求是否被理解或被满足。原因分析是
    用简短的文字来描述状态代码产生的原因。状态代码用来支持自动操作,原因分析是为人类
    用户准备的。客户端不需要检查或显示原因分析。
     
     状态代码的第一位数字定义了回应的类别,后面两位数字没有具体分类。首位数字有5
    种取值可能:
    o 1xx::保留,将来使用。
    o 2xx:成功 - 操作被接收、理解、接受(received, understood, accepted)。
    o 3xx:重定向(Redirection)-要完成请求必须进行进一步操作。
    o 4xx:客户端出错 - 请求有语法错误或无法实现。
    o 5xx:服务器端出错 - 服务器无法实现合法的请求。
    HTTP/1.0的状态代码、原因解释在下面给出。下面的原因解释只是建议采用,可任意
    更改,而不会对协议造成影响。完整的代码定义在第9节。
           Status-Code    = "200"   ; OK
                          | "201"   ; Created
                          | "202"   ; Accepted
                          | "204"   ; No Content
                          | "301"   ; Moved Permanently
                          | "302"   ; Moved Temporarily
                          | "304"   ; Not Modified
                          | "400"   ; Bad Request
                          | "401"   ; Unauthorized
                          | "403"   ; Forbidden
                          | "404"   ; Not Found
                          | "500"   ; Internal Server Error
                          | "501"   ; Not Implemented
                          | "502"   ; Bad Gateway
                          | "503"   ; Service Unavailable
                          | extension-code
           extension-code = 3DIGIT
           Reason-Phrase  = *<TEXT, excluding CR, LF>
     HTTP状态代码是可扩展的,而只有上述代码才可以被当前全部的应用所识别。HTTP
    应用不要求了解全部注册的状态代码,当然,如果了解了更好。实际上,应用程序必须理解
    任何一种状态代码,如果碰到不识别的情况,可根据其首位数字来判断其类型并处理。另外,
    不要缓存无法识别的回应。
     例如,如果客户端收到一个无法识别的状态码431,可以安全地假定是请求出了问题,
    可认为回应的状态码就是400。在这种情况下,用户代理应当在回应消息的实体中通知用户,
    因为实体中可以包括一些人类可以识别的非正常状态的描述信息。

  • 相关阅读:
    Object C语法学习
    iOS9的几个新关键字(nonnull、nullable、null_resettable、__null_unspecified)
    系统迭代新功能及第三方技术
    码云&Github 个人代码资源快速查找
    iOS开发应用结构化资源储备
    新增扩展程序功能打包提交新版 WARNING ITMS-90473 警告问题
    NSRect 位置和尺寸
    iOS应用打包完后再在开发者网站添加应用测试ID能够加入测试吗
    苹果原生文字转语音播报
    SiriShortCut模型建立及数据交互逻辑
  • 原文地址:https://www.cnblogs.com/gs-34/p/10437999.html
Copyright © 2011-2022 走看看