读 HTTP 协议

来源:互联网 发布:mac风扇一直转 编辑:程序博客网 时间:2024/06/05 23:46

文章链接: http://harttle.com/2014/10/01/http.html

超文本传输协议(英文: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

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

   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:保留,用作代理。

Request 头

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
  • 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头部字段如下:

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),服务器将根据指定的Range Unitrange将实体划分为subrange返回给客户端。

    该字段允许服务器指定接受怎样的range请求。例如:

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

缓存

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

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

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

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

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

状态码

以下给出状态码说明,其描述参见wikipedia:HTTP状态码

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

HTTP表单

在web开发中最常见的莫过于GET和POST,其中GET一般将参数编码在url中(HTTP header)来传递数据;
而POST或PUT数据必须放在消息主体(entity-body)中,这样的数据便是HTTP表单,表单数据的编码方式应在HTTP头中进行设置(Content-Type header字段),常见的编码方式有(HTTP采用MIME框架,编码方式可以是任何MIME类型):

  • urlencoded
  • multipart
  • json
  • plain text
  • xml

在Web开发中,前三种格式非常常见。HTML中<form>支持urlencoded,multipart,plain text,通过enctype属性来进行设置。AJAX中默认的则是JSON编码格式。

urlencoded

HTML中<form>标签的enctype属性用来指定表单编码格式,默认为application/x-www-form-urlencoded,即以下两个表单完全等价。

<form method='post'>  <input type="text" name='title'>  <input type="text" name='subtitle'>  <input type="submit"></form>
<form  method='post' enctype='application/x-www-form-urlencoded'>  <input type="text" name='title'>  <input type="text" name='subtitle'>  <input type="submit"></form>

上述表单将会显示为两个文本框和一个提交按钮。我们在文本框中分别写入test中国后,点击提交按钮。产生的HTTP请求可能是这样的:

可以打开Chrome控制台的Network标签,找到这次请求,便可以看到下面的信息。

请求头(这里只给出了Content-Type字段):

POST http://www.example.com HTTP/1.1Content-Type: application/x-www-form-urlencoded

请求体:

title=test&subtitle=%E4%B8%AD%E5%9B%BD

这里你看到的%E4%B8%AD%E5%9B%BD即是中国按照base64编码(url通用的编码方式)后的结果。可以在Chrome Console中通过decodeURI('%E4%B8%AD%E5%9B%BD')来解码。

multipart

multipart编码方式则需要设置enctypemultipart/form-data

<form method="post" enctype="multipart/form-data">    <input type="text" name="title" value="harttle">    <input type="file" name="avatar">    <input type="submit"></form>

这里我们还设置了<input type='text'>的默认值为harttle

该表单将会显示为一个文本框、一个文件按钮、一个提交按钮。然后我们选择一个文件:chrome.png,点击表单提交后产生的请求可能是这样的:

请求头:

POST http://www.example.com HTTP/1.1Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA

请求体:

------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="title"harttle------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name="avatar"; filename="chrome.png"Content-Type: image/png ... content of chrome.png ...------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这便是一个multipart编码的表单。Content-Type中还包含了boundary的定义,它用来分隔请求体中的每个字段。正是这一机制,使得请求体中可以包含二进制文件(当然文件中不能包含boundary)。

除了application/x-www-form-urlencodedmultipart/form-data,HTML的<form>还支持text/plain。此外,如果想提交其他编码类型的表单,必须通过AJAX技术,接下来我们介绍一个常用的JSON数据的提交。

json

从JavaScript中提交JSON数据真是再方便不过了,jquery、angularJS等框架都封装了更好用的AJAX方法。例如:

$.post('/xxx', {        title: 'test',        content: [1,2,3]    });

该JavaScript执行后可能生成如下的HTTP请求:

请求头:

POST http://www.example.com HTTP/1.1Content-Type: application/json;charset=utf-8

请求体:

{"title":"test","content":[1,2,3]}

xml

请求头:

POST http://www.example.com HTTP/1.1Content-Type: text/xml

请求体:

<!--?xml version="1.0"?--><methodcall>    <methodname>examples.getStateName</methodname>    <params>        <param>            <value><i4>41</i4></value>    </params></methodcall>

参考:RTF 2616

0 0