超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP) 是互联网上应用最为广泛的一种网络协议。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。通过HTTP或者HTTPS协议请求的资源由 统一资源标识符(Uniform Resource Identifiers,URI) 来标识。

HTTP协议标准是由万维网协会(World Wide Web Consortium,W3C)和互联网工程任务组(Internet Engineering Task Force,IETF)制定的,其中最著名的是RFC-2616,定义了HTTP协议中现今广泛使用的一个版本—HTTP 1.1。

第一个版本的HTTP(HTTP/0.9)用于Internet上的传输原始数据;HTTP/1.0加入了MIME支持、元数据、请求/应答限定符。

对web开发者而言HTTP协议的用法已耳熟能详,本文只记录与web开发相关的HTTP重要细节。

HTTP是一种通用的、无状态的应用层协议,适用于分布式、协同的、超媒体信息系统。通过一些扩展(如请求方法、错误码、头信息),HTTP可用于超文本外的其他用途,例如命名服务器、分布式对象管理。HTTP的特点在于数据表示的类型与协商,允许建立系统时不必考虑数据是如何传输的。

操作

多数HTTP通信由用户代理发起请求,服务器响应该请求。更复杂的情况则可能包括代理、网关和隧道。 代理 是指转发代理,它接受URI请求,重写部分消息,然后把重写过的消息转发至URI标识的服务器。 网关 是指接收代理,它运行在其他服务器之上,需要时可以为背后的服务器翻译请求。 隧道 相当于两个连接的中转站,但不会改变消息。当通信需要通过一个中介时可以使用隧道,即使该中介不理解消息内容。

   request chain -------------------------------------->
UA -----v----- A -----v----- B -----v----- C -----v----- O
   <------------------------------------- response chain

除隧道外的通信方都可能会采用内部缓存和处理消息,缓存可以缩短请求/应答链。但并不是所有消息都可以被缓存,缓存行为也在RFC-2616中加以定义。

   request chain ---------->
UA -----v----- A -----v----- B - - - - - - C - - - - - - O
   <--------- response chain

HTTP通常发生在TCP/IP连接上,默认的TCP端口为80,当然也可以使用别的端口。这不会影响到HTTP实现,HTTP只假设有一个可靠的传输协议。

HTTP/1.1连接应该是持久连接。这不仅能够减小TCP连接的内存、CPU开销,减小了TCP包的数量,同时提供了更短的延迟和及时的错误反馈。此时,请求与应答可以形成管道而不必等上一个连接的关闭。

URI

在HTTP中,URI 是用来标识资源的字符串。

http_URL = "http:" "//" host [ ":" port ] [ abs_path [ "?" query ]]

HTTP URI 是大小写敏感的,相同的URI应该每个字节都完全相同。除非:

  1. 端口空。此时相当于默认端口。
  2. 主机名必须大小写无关。
  3. 模式名必须大小写无关。
  4. 绝对路径为空。此时相当于/

HTTP方法

  • GET:获取URI制定的信息。
  • HEAD:同GET,但服务器不返回消息体。
  • POST:请求服务器接受请求中包装的实体,将其作为URI标识的资源的附属信息。
  • PUT:让服务器将请求中包装的实体存储为URI标识位置。
  • DELETE:让服务器将URI标识的资源删除。
  • TRACE:调用远程的应用层环回。最终服务器应将收到的消息包装为实体并返回状态码为200的应答。
  • CONNECT:保留,用作代理。

其中HEADGET被称为安全方法,即服务器只是返回所需的信息,不应该产生其他的副作用。

HTTP 头字段简介

HTTP 头字段包括通用头字段(general-header),请求头字段(request-header),响应头字段(response-header)和实体头字段(entity-header)。

每个头字段包括字段名与字段只,以冒号:分隔。其中字段名大小写不敏感。

通用头字段

通用头字段对于HTTP请求和响应均可用,用来描述HTTP消息(HTTP message)本身, 不可用来描述被传输的实体(HTTP entity)。共9个:

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
  • Cache-Control:指定整个请求链中必须遵循的缓存指令,是单向的。其值包括max-ageno-cache等。
  • Connection:发送者用来指定连接选项,属于hop by hop头字段,不可被代理传递。例如Websocket建立连接时的Handshake HTTP Request,包含Connection: upgradeUpgrade: Websocket头字段。
  • Date:请求或响应的时间和日期。
  • Pragma:用来指定实现相关(implementation-specific)的指令,例如:Pragma: no-cache
  • Transfer-Encoding:为了使消息安全到达,HTTP消息经过了何种转换,例如Transfer-Encoding: chunked
  • Via:HTTP消息传送期间经过了何种协议或代理,网关和代理必须实现该字段。如Via: 1.0 fred, 1.1 nowhere.com (Apache/1.1)

请求头字段

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
  • Accept:可接受的应答的媒体类型,可使用通配符*

      Accept: autio/*; q=0.2, autio/basic
      # 最好是basic音频,如果没有的话任何音频都可以接受(这时我认为质量打了80%的折扣)
    
  • Accept-Charset:可接受的应答的字符集。

      Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
      # 最好是iso-8859-5,不过unicode-1-1也还好(80%的质量)
    
  • Accept-Encoding:可接受的应答的内容编码。

      Accept-Encoding: gzip;q=1.0, identity; q=0.5, *;q=0
    
  • Accept-Language:可接受的应答的自然语言集合。

      Accept-Language: da, en-gb;q=0.8, en;q=0.7
    
  • Authorization:用户想要让服务器给自己授权,通常在接受到401之后发生。
  • Expect:客户需要的服务器行为。

    该字段是逐跳发生的,即代理如不能满足该期望应返回417;但请求头是端到端的,该请求仍然必须被转发。

  • From:该字段应为控制发送请求的HTTP代理(agent)的用户电子邮箱名。
  • Host:目标主机名与端口,来自URI。
  • If-Match:与HTTP方法一起用,使得条件性执行该方法。条件为该实体匹配该列表,即没有发生用户所不知道的变化。

在HTTP中,质量值qvalue作为协商参数的限定符,表示客户端认为该参数的重要性(权重)。如果一个参数qvalue为0,表示该参数对客户端来讲是不可接受的。参数之间用,分隔,参数值与质量值之间用;分隔。

响应头字段

response头部字段如下:

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
  • Accept-Ranges

    在HTTP/1.1中,客户端可以请求部分的应答(range),服务器将根据指定的单位和Request的Range将实体划分为subrange返回给客户端。

    该字段允许服务器指定接受怎样的range请求。例如Accept-Ranges: bytes表示接受以byte为单位的Range

  • Age:生成该response以来,服务器估计已经过去了多少时间。该字段用于缓存机制。
  • ETag:指定请求变量的当前实体Tag。该字段用来比较来自同一资源的变化的实体。与If-Match/If-None-Match成对使用来实现缓存。
  • Location:为完成请求或标识新的资源,服务器用该字段将接收者重定向。此处应指定绝对路径。
  • Proxy-Authenticate407(Proxy Authentication Required)响应必须填写该字段。该字段应指出授权模式和该URI代理的参数。收到该响应后代理应寻找自己的授权证书。该字段只用于当前连接(点到点),不应传到下游的客户端。
  • Retry-After:用于503(Service Unavailable)响应。指示客户端服务预期多久不可用。可以是绝对时间,也可以是代表时间间隔的整数(单位为秒)。
  • Server:原始服务器处理该请求的软件信息。
  • Vary:指示不可缓存的请求头列表(大小写不敏感)。
  • WWW-Authenticate401(Unauthorized)响应必须填写该字段。同Proxy-Authenticate,只不过该字段作用于用户代理(User Agent)。

实体头字段

实体头字段(entity )用来表示HTTP实体(entity body)的元信息。 如果实体(HTTP body)不存在,则表示HTTP请求所标识的资源的元信息。

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
  • Allow:实体允许哪些方法,例如:Allow: GET, HEAD, PUT
  • Content-Encoding:内容编码,这是对Content-Type的进一步修饰,例如Content-Encoding: gzip
  • Content-Location的值是绝对或相对URI,表示请求体的资源处于何处。
  • Content-Type:资源的媒体类型,例如Content-Type: text/html; charset=ISO-8859-4
  • Expires:过期时间,例如Expires: Thu, 01 Dec 1994 16:00:00 GMT
  • Last-Modified:服务器认为该资源上次修改的时间,格式同上。与Not-Modified-Since成对使用可实现缓存。

缓存

HTTP常用语信息系统,此时应答缓存可以提高性能。缓存应该保证是正确的,如果一个应答的缓存既非一手的,又不够新,则必须在应答中添加警告。

HTTP/1.1的基本缓存机制只有隐式的缓存指示,在有些系统中需要给出明确的缓存指示。此时要用到缓存控制(Cache-Control)头。

最好的缓存应完全避免从原始服务器发送请求,主要的机制是服务器明确给定应答的过期时间。相反地,服务其可以将过期时间设为过去的时间, 以此强制得到最新的请求。过期时间的计算有两种方法:

  1. now - Age Header,其中Age Header是生成应答时服务器会设置的字段。
  2. age_value,等于该应答在所有缓存中驻留的时间和,加上所有路径上传输所用的时间。

当然,缓存服务器之间需要通过类似NTP的协议来同步他们的时钟。

在Web应用中,缓存通常通过EtagExpires响应头来实现。Etag表示资源的ID,Expires表示资源的过期时间。 User-Agent(比如浏览器)可以通过这两个字段来恰当地缓存这些HTTP响应。

状态码

HTTP状态码(HTTP Status Code)是用以表示Web服务器HTTP响应状态的3位数字代码,分为5大类。 以下给出状态码说明,其描述参见wikipedia:HTTP状态码

  • 1xx:表示请求已被接受,但需要后续处理。
  • 2xx:请求已成功被服务器接收、理解、并接受。
  • 3xx:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向, 重定向目标在本次响应的Location头字段中指明。
  • 4xx:这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。 除非响应的是一个HEAD请求,否则服务器就应该返回一个解释当前错误状况的实体。
  • 5xx:这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。 并且响应消息体中应当给出理由,除非是HEAD请求。

常见的响应状态码在如何理解HTTP响应的状态码?一文有详细介绍。

参考连接

RTF 2616: http://tools.ietf.org/html/rfc2616

本文采用 知识共享署名 4.0 国际许可协议(CC-BY 4.0)进行许可,转载注明来源即可: https://harttle.land/2014/10/01/http.html。如有疏漏、谬误、侵权请通过评论或 邮件 指出。