HTTP 协议简介

HTTP (HyperText Transfer Protocol, 超文本传输协议)是互联网上应用最为广泛的一种网络协议,它是基于 TCP应用层协议,简单地说就是客户端和服务器进行通信的一种规则,它的模式非常简单,就是客户端发起请求,服务器响应请求,如下图所示:

HTTP 最早于 1991 年发布,是 0.9 版,不过目前该版本已不再用。HTTP 目前在使用的版本主要有:

  • HTTP/1.0,于 1996 年 5 月发布,引入了多种功能,至今仍在使用当中。
  • HTTP/1.1,于 1997 年 1 月发布,持久连接被默认采用,是目前最流行的版本。
  • HTTP/2 ,于 2015 年 5 月发布,引入了服务器推送等多种功能,是目前最新的版本。

HTTP 请求

HTTP 请求由三部分组成:

  • 请求行:包含请求方法、请求地址和 HTTP 协议版本
  • 消息报头:包含一系列的键值对
  • 请求正文(可选):注意和消息报头之间有一个空行

如图所示:

下面是一个 HTTP GET 请求的例子:

GET / HTTP/1.1
Host: httpbin.org
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 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;q=0.6,zh-TW;q=0.4
Cookie: _ga=GA1.2.475070272.1480418329; _gat=1

上面的第一行就是一个请求行

GET / HTTP/1.1

其中,GET 是请求方法,表示从服务器获取资源;/ 是一个请求地址;HTTP/1.1 表明 HTTP 的版本是 1.1。

请求行后面的一系列键值对就是消息报头

Host: httpbin.org
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 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;q=0.6,zh-TW;q=0.4
Cookie: _ga=GA1.2.475034215.1480418329; _gat=1

其中:

  • Host 是请求报头域,用于指定被请求资源的 Internet 主机和端口号,它通常从 HTTP URL 中提取出来;
  • Connection 表示连接状态,keep-alive 表示该连接是持久连接(persistent connection),即 TCP 连接默认不关闭,可以被多个请求复用,如果客户端和服务器发现对方有一段时间没有活动,就可以主动关闭连接;
  • Cache-Control 用于指定缓存指令,它的值有 no-cache, no-store, max-age 等,max-age=秒表示资源在本地缓存多少秒;
  • User-Agent 用于标识请求者的一些信息,比如浏览器类型和版本,操作系统等;
  • Accept 用于指定客户端希望接受哪些类型的信息,比如 text/html, image/gif 等;
  • Accept-Encoding 用于指定可接受的内容编码;
  • Accept-Language 用于指定可接受的自然语言;
  • Cookie 用于维护状态,可做用户认证,服务器检验等,它是浏览器储存在用户电脑上的文本片段;

HTTP 请求方法

HTTP 通过不同的请求方法以多种方式来操作指定的资源,常用的请求方法如下表:

方法 描述
GET 从服务器获取指定(请求地址)的资源的信息,它通常只用于读取数据,就像数据库查询一样,不会对资源进行修改。
POST 向指定资源提交数据(比如提交表单,上传文件),请求服务器进行处理。数据被包含在请求正文中,这个请求可能会创建新的资源或更新现有的资源。
PUT 通过指定资源的唯一标识(在服务器上的具体存放位置),请求服务器创建或更新资源。
DELETE 请求服务器删除指定资源。
HEAD 与 GET 方法类似,从服务器获取资源信息,和 GET 方法不同的是,HEAD 不含有呈现数据,仅仅是 HTTP 头信息。HEAD 的好处在于,使用这个方法可以在不必传输全部内容的情况下,就可以获得资源的元信息(或元数据)。
OPTIONS 该方法可使服务器传回资源所支持的所有 HTTP 请求方法。

HTTP 响应

HTTP 响应与 HTTP 请求相似,由三部分组成:

  • 状态行:包含 HTTP 协议版本、状态码和状态描述,以空格分隔
  • 响应头:即消息报头,包含一系列的键值对
  • 响应正文:返回内容,注意和响应头之间有一个空行

如图所示:

下面是一个 HTTP GET 请求的响应结果:

HTTP/1.1 200 OK
Server: nginx
Date: Tue, 29 Nov 2016 13:08:38 GMT
Content-Type: application/json
Content-Length: 203
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "args": {}, 
  "headers": {
    "Host": "httpbin.org", 
    "User-Agent": "Paw/2.3.1 (Macintosh; OS X/10.11.3) GCDHTTPRequest"
  }, 
  "origin": "13.75.42.240", 
  "url": "https://httpbin.org/get"
}

上面的第一行就是一个状态行

HTTP/1.1 200 OK

其中,200 是状态码,表示客户端请求成功,OK 是相应的状态描述。

状态码是一个三位的数字,常见的状态码有以下几类:

  • 1XX 消息 -- 请求已被服务接收,继续处理
  • 2XX 成功 -- 请求已成功被服务器接收、理解、并接受
    • 200 OK
    • 201 Created 已创建
    • 202 Accepted 接收
    • 203 Non-Authoritative Information 非认证信息
    • 204 No Content 无内容
  • 3XX 重定向 -- 需要后续操作才能完成这一请求
    • 301 Moved Permanently 请求永久重定向
    • 302 Moved Temporarily 请求临时重定向
    • 304 Not Modified 文件未修改,可以直接使用缓存的文件
    • 305 Use Proxy 使用代理
  • 4XX 请求错误 -- 请求含有词法错误或者无法被执行
    • 400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解
    • 401 Unauthorized 请求未经授权。这个状态代码必须和WWW-Authenticate报头域一起使用
    • 403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因
    • 404 Not Found 请求的资源不存在,例如,输入了错误的URL
  • 5XX 服务器错误 -- 服务器在处理某个正确请求时发生错误
    • 500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求
    • 503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常
    • 504 Gateway Time-out 网关超时

状态行后面的一系列键值对就是消息报头,即响应头:

Server: nginx
Date: Tue, 29 Nov 2016 13:08:38 GMT
Content-Type: application/json
Content-Length: 203
Connection: close
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

其中:

  • Server 包含了服务器用来处理请求的软件信息,跟请求报头域 User-Agent 相对应;
  • Content-Type 用于指定发送给接收者(比如浏览器)的响应正文的媒体类型,比如 text/html, text/css, image/png, image/jpeg, video/mp4, application/pdf, application/json 等;
  • Content-Length 指明本次回应的数据长度;

再议 POST 和 PUT

注意到,POST 和 PUT 都可用于创建或更新资源,然而,它们之间还是有比较大的区别:

  • POST 所对应的 URI 并非创建的资源本身,而是资源的接收者,资源本身的存放位置由服务器决定;而 PUT 所对应的 URI 是要创建或更新的资源本身,它指明了具体的存放位置

比如,往某个站点添加一篇文章,如果使用 POST 来创建资源,可类似这样:

POST /articles HTTP/1.1

{
    "author": "ethan",
    "title": "hello world",
    "content": "hello world"
}

在上面,POST 对应的 URI 是 /articles,它是资源的接收者,而非资源的标识,如果资源被成功创建,服务器可以返回 201 Created 状态以及新建资源的位置,比如:

HTTP/1.1 201 Created
Location: /articles/abcdef123

我们如果知道新建资源的标识符,可以使用 PUT 来创建资源,比如:

PUT /articles/abcdef234 HTTP/1.1

{
    "author": "peter",
    "title": "hello world",
    "content": "hello world"
}

在上面,PUT 对应的 URI 是 /articles/abcdef234,它指明了资源的存放位置,如果资源被成功创建,服务器可以返回 201 Created 状态以及新建资源的位置,比如:

HTTP/1.1 201 Created
Location: /articles/abcdef234
  • 使用 PUT 更新某一资源,需要更新资源的全部属性;而使用 POST,可以更新全部或一部分值

比如使用 PUT 更新地址为 /articles/abcdef234 的文章的标题,我们需要发送所有值:

PUT /articles/abcdef234 HTTP/1.1

{
    "author": "peter",
    "title": "hello python",
    "content": "hello world"
}

而使用 POST,可以更新某个域的值:

POST /articles/abcdef234 HTTP/1.1

{
    "title": "hello python"
}
  • POST 是不幂等的,PUT 是幂等的,这是一个很重要的区别

HTTP 方法的幂等性是指一次和多次请求某一个资源应该具有同样的副作用,注意这里是副作用,而不是返回结果。

GET 方法用于获取资源,不会改变资源的状态,不论调用一次还是多次都没有副作用,因此它是幂等的;DELETE 方法用于删除资源,有副作用,但调用一次或多次都是删除同个资源,产生的副作用是相同的,因此也是幂等的;POST 是不幂等的,因为两次相同的 POST 请求会在服务器创建两份资源,它们具有不同的 URI;PUT 是幂等的,对同一 URI 进行多次 PUT 的副作用和一次 PUT 是相同的。

HTTP 特点

  • 客户端/服务器模式
  • 简单快速:客户端向服务器请求服务时,通过传送请求方法、请求地址和数据体(可选)即可
  • 灵活:允许传输任意类型的数据对象,通过 Content-Type 标识
  • 无状态:对事物处理没记忆能力

小结

  • HTTP 是在网络上传输 HTML 的协议,用于浏览器和服务器的通信,默认使用 80 端口。
  • URL 地址用于定位资源,HTTP 中的 GET, POST, PUT, DELETE 用于操作资源,比如查询,增加,更新等。
  • GET, PUT, DELETE 是幂等的,POST 是不幂等的。
  • POST VS PUT
    • 使用 PUT 创建资源需要提供资源的唯一标识(具体存放位置),POST 不需要,POST 的数据存放位置由服务器自己决定
    • 使用 PUT 更新某一资源,需要更新资源的全部属性;而使用 POST,可以更新全部或一部分值
    • POST 是不幂等的,PUT 是幂等的,这是一个很重要的区别
  • GET 可提交的数据量受到 URL 长度的限制,HTTP 协议规范没有对 URL 长度进行限制,这个限制是特定的浏览器及服务器对它的限制。
  • 理论上讲,POST 是没有大小限制的,HTTP 协议规范也没有进行大小限制,出于安全考虑,服务器软件在实现时会做一定限制。

参考资料