HTTP 是超文本传输协议 (HyperText Transfer Protocol) 的缩写,是互联网上应用最为广泛的一种网络协议。通过 HTTP 或者 HTTPS 协议请求的资源由统一资源标识符(Uniform Resource Identifies, URI) 来标识。

HTTP 构建与 TCP/IP 协议之上,默认端口是 80。

请求报文

HTTP 协议规范把 HTTP 请求分为:请求行、请求头、空行、请求消息体。类似于下面这样:

1
2
3
4
<method> <request-URL> <version>
<headers>

<entity-body>

其中,请求头和请求行必须以 <CR><CF> 作为结尾。空行内必须只有 <CR><CF> 而无其他空格。在 HTTP/1.1 协议中,所有的请求头,除 Host 外,都是可选的。

以下是访问 https://www.locket.tt 的请求报文:

1
2
3
4
5
6
7
8
GET / HTTP/1.1
Host: www.locket.tt
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4

第 1 行为请求行,其中 GET 是请求方法,/ 为请求资源路径, HTTP/1.1 为所使用的 HTTP 协议版本;

第 2 行至第 9 行为请求头,其中 Host 指定了主机地址为 www.locket.tt。

GET 方法一般是没有请求消息体的,所有请求报文中只有请求行和请求头。

请求方法

HTTP/1.1 协议中共定义了八种方法来以不同方式操作指定的资源:

  • OPTIONS:这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用’*’来代替资源名称,向Web服务器发送OPTIONS请求,可以测试服务器功能是否正常运作。
  • HEAD:与GET方法一样,都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获取其中“关于该资源的信息”(元信息或称元数据)。
  • GET:向指定的资源发出“显示”请求,使用GET方法应该只用在读取数据。
  • POST:向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
  • PUT:向指定资源位置上传其最新内容。
  • DELETE:请求服务器删除Request-URI所标识的资源。
  • TRACE:回显服务器收到的请求,主要用于测试或诊断。
  • CONNECT:HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。通常用于SSL加密服务器的链接(经由非加密的HTTP代理服务器)。

其中方法名是区分大小写的。当某个请求所针对的资源不支持对应的请求方法的时候,服务器会返回 405 状态码(Method Not Allowed),当服务器不认识或者不支持对应的请求方法的时候,应当返回 501 状态码(Not Implemented)。

HTTP/1.1 协议要求服务器至少应该实现 GET 和 HEAD 方法,其他方法都是可选的。当然我们最常用的还是 GET、POST、PUT、DELETE 等 4 种方法。

通常我们在网页中填写信息,一般会使用 POST 方法,请求报文大概如下:

1
2
3
4
5
6
7
8
9
10
11
12
POST / HTTP/1.1
Host: www.locket.tt
Connection: keep-alive
Content-Length: 38
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4

name=locket&email=service@zenzet.com

第 1 行定义了通过 POST 请求方法提交数据;

第 4 行 的 Cointent-Type 定义了请求消息体的内容长度;

第 6 行 Content-Type 定义了请求消息体的内容格式:application/x-www-form-urlencoded,application/x-www-form-urlencoded 类型的数据,会按照 Url 编码将 body 内容编码后发往服务器。

第 11 行为消息体内容。

响应报文

HTTP 响应报文与请求报文类似,分为:状态行、响应头、空行、响应消息体。类似于下面这样:

1
2
3
4
<version> <status> <reason-phrase>
<headers>

<entity-body>

以下是响应报文示例:

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Date: Sun, 30 Apr 2017 02:55:45 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 42
Connection: keep-alive
ETag: W/"7327-W/VsZ13C3Q5gt8dbytBcY/EfP1U"
Content-Encoding: gzip

<html>
<body>Hello World</body>
</html>

第 3 行 Content-Type 指定了响应消息体的内容格式。

Content-Type

上文中的请求报文和响应报文示例均在 Header 中指定了 Content-Type 字段,在请求报文中,用于客户端告诉服务端请求数据格式;在响应报文中,用于服务器端告诉客户端相应数据格式。

下面是一些常见的 Content-Type 字段的值:

  • text/plain
  • text/html
  • text/css
  • image/jpeg
  • image/png
  • audio/mp3
  • video/mp4
  • application/javascript
  • application/xml
  • application/json
  • application/x-www-form-urlencoded
  • multipart/form-data

其中 application/x-www-form-urlencoded 和 multipart/form-data 用于请求报文中,application/x-www-form-urlencoded 多用于普通表单提交,multipart/form-data 用于上传文件。

以下是上传文件到百度网盘的请求报文:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
POST /rest/2.0/pcs/superfile2?method=upload&app_id=123456&channel=chunlei&clienttype=0&web=1&path=/hello.txt HTTP/1.1
Host: c3.pcs.baidu.com
Connection: keep-alive
Content-Length: 204
Origin: https://pan.baidu.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.81 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFPu1lm1ZYFB7tHve
Accept: */*
Referer: https://pan.baidu.com/disk/home
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4

------WebKitFormBoundaryFPu1lm1ZYFB7tHve
Content-Disposition: form-data; name="file"; filename="blob"
Content-Type: application/octet-stream

Hello World

------WebKitFormBoundaryFPu1lm1ZYFB7tHve--

multipart/form-data 通过在 Content-Type 中设定 boundary (—-WebKitFormBoundaryFPu1lm1ZYFB7tHve) ,在 body 中通过 boundary 来分隔不同的字段,第 17 行即为上传文件内容。

Content-Encoding

由于发送的数据可以是任何格式,因此可以把数据压缩后发送。Content-Encoding 字段说明数据的压缩方法。

1
2
3
Content-Encoding: gzip
Content-Encoding: compress
Content-Encoding: deflate

客户端在请求时用 Accept-Encoding 字段说明可接收的压缩方法:

1
Accept-Encoding: gzip, deflate

其他

HTTP/1.1 版本引入了持久连接,即TCP连接默认不关闭,可以被多个请求复用,不用声明Connection: keep-alive

服务器端发送回应前,在不知道回应的数据长度时,是无法指定 Content-Length 字段来声明响应消息体大小,在 HTTP/1.1 版本中增加了分块传输编码支持:Transfer-Encoding: chunked 。每个非空的数据块之前,会有一个16进制的数值,表示这个块的长度。最后是一个大小为0的块,就表示本次回应的数据发送完了。

参考:

Hypertext_Transfer_Protocol