HTTP协议

基础概念

请求和响应报文

客户端发送一个请求报文给服务器,服务器根据请求报文中的信息进行处理,并将处理结果放入响应报文中返回给客户端。

请求报文结构:

  • 第一行是包含了请求方法、URL、协议版本;
  • 接下来的多行都是请求首部Header,每个首部都有一个首部名称,以及对应的值;
  • 一个空行用来分隔首部和内容主体Body
  • 最后是请求的内容主体

1
2
3
4
5
6
7
8
9
10
11
12
13
GET http://www.example.com/ HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cache-Control: max-age=0
Host: www.example.com
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
If-None-Match: "3147526947+gzip"
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 xxx

param1=1&param2=2

响应报文结构:

  • 第一行包含协议版本、状态码以及描述,最常见的是200 OK 表示请求成功
  • 接下来多行也是首部内容
  • 一个空行分隔首部和内容主体
  • 最后是响应的内容主体
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
HTTP/1.1 200 OK
Age: 529651
Cache-Control: max-age=604800
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 648
Content-Type: text/html; charset=UTF-8
Date: Mon, 02 Nov 2020 17:53:39 GMT
Etag: "3147526947+ident+gzip"
Expires: Mon, 09 Nov 2020 17:53:39 GMT
Keep-Alive: timeout=4
Last-Modified: Thu, 17 Oct 2019 07:18:26 GMT
Proxy-Connection: keep-alive
Server: ECS (sjc/16DF)
Vary: Accept-Encoding
X-Cache: HIT

<!doctype html>
<html>
<head>
<title>Example Domain</title>
// 省略...
</body>
</html>

URL

HTTP使用URL(统一资源定位符)来定位资源,它是URI(统一资源标识符)的子集,URL在URI的基础上增加了定位能力。URI除了包含URL,还包含URN(统一资源名称),它只是用来定义一个资源的名称,并不具备定位该资源的能力 。

HTTP方法

客户端发送的请求报文第一行为请求行,包含了方法字段。

  • GET:获取资源,当前网络请求中,绝大部分使用的是GET方法
  • HEAD:获取报文首部,和GET方法类似,但是不返回报文实体主体部分。主要用于确认URL的有效性以及资源更新的日期时间等。
  • POST:传输实体主体,主要用来传输数据,而GET主要用来获取资源。
  • PUT:上传文件,由于自身不带验证机制,任何人都可以上传文件,因此存在安全性问题,一般不使用该方法。
  • PATCH:对资源进行部分修改:PUT也可以用于修改资源,但是只能完全代替原始资源,PATCH允许部分修改。
  • DELETE:删除文件,与PUT功能相反,并且同样不带验证机制。
  • OPTIONS:查询支持的方法,查询指定的URL能够支持的方法。会返回Allow:GET、POST、HEAD、OPTIONS这样的内容。
  • CONNECT:要求在与代理服务器通信时建立隧道,使用SSL(安全套接层)和TLS(传输层安全)协议把通信内容加密后经过网络隧道传输。
  • TRACE:追踪路径,服务器会将通信路径返回给客户端。发送请求时,在Max-Forwards首部字段中填入数值,每经过一个服务器就会减1,当数值为0时就停止传输。通常不会使用TRACE,并且它容易受到XST攻击。

HTTP状态码

服务器返回响应报文中第一行为状态行,包含了状态码以及原因短语,用来告知客户端请求的结果。

状态码 类别 含义
1XX 信息性状态码 接受的请求正在处理
2XX 成功状态码 请求正常处理完毕
3XX 重定向状态码 需要进行附加操作以完成请求
4XX 客户端错误状态码 服务器无法处理请求
5XX 服务器错误状态码 服务器处理请求出错

1XX 信息

  • 100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。

2XX 成功

  • 200 OK
  • 204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
  • 206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。

3XX 重定向

  • 301 Moved Permanently :永久性重定向
  • 302 Found :临时性重定向
  • 303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
  • 注:虽然 HTTP 协议规定 301、302 状态下重定向时不允许把 POST 方法改成 GET 方法,但是大多数浏览器都会在 301、302 和 303 状态下的重定向把 POST 方法改成 GET 方法。
  • 304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
  • 307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。

4XX 客户端错误

  • 400 Bad Request :请求报文中存在语法错误。
  • 401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
  • 403 Forbidden :请求被拒绝。
  • 404 Not Found

5XX 服务端错误

  • 500 Internal Server Error :服务器正在执行请求时发生错误。
  • 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

HTTP首部

有四种类型的首部字段:通用首部字段、请求首部字段、响应首部字段和实体首部字段。

具体应用

连接管理

短连接与长连接

当浏览器访问一个包含多张图片的HTML页面时,除了请求访问的HTML页面资源,还会请求图片资源。如果每进行一次HTTP通信就要新建一个TCP连接,那么开销会很大。

长连接只需要建立一次TCP连接就能进行多次HTTP通信。

  • 从HTTP/1.1开始默认是长连接,如果要断开连接,需要由客户端或者服务器提出断开,使用Connection:close;
  • 在HTTP/1.1之前默认是短连接的,如果需要使用长连接,则使用Connection:Keep-Alive。

流水线

默认情况下,HTTP请求是按顺序发出的,下一个请求只有在当前请求收到响应之后才会被发出。由于受到网络延迟和带宽限制,在下一个请求被发送到服务器之前,可能需要等待很长的时间。

流水线是在同一条长连接上连续发出请求,而不用等待响应返回,这样可以减少延迟。

HTTP协议是无状态的,主要是为了让HTTP协议尽可能简单,使得它能够处理大量事务。HTTP/1.1引入Cookie来保存状态信息。

Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器之后向同一服务器再次发起请求时被携带上,用于告知服务端两个请求是否来自同一浏览器。由于之后每次请求都会需要携带Cookie数据,因此会带来额外的性能开销。

Cookie曾一度用于客户端数据的存储,因为当时并没有其他合适的存储办法而作为唯一的存储手段,但现在随着现代浏览器开始支持各种各样的存储方式,Cookie渐渐被淘汰。新的浏览器API已经允许开发者直接将数据存储到本地,如使用Web storage API或IndexedDB。

用途

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其他需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等)

创建过程

服务器发送的响应报文包含 Set-Cookie 首部字段,客户端得到响应报文后把 Cookie 内容保存到浏览器中。

客户端之后对同一个服务器发送请求时,会从浏览器中取出 Cookie 信息并通过 Cookie 请求首部字段发送给服务器。

分类

  • 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。
  • 持久性 Cookie:指定过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。

Session

除了可以将用户信息通过Cookie存储在用户浏览器中,也可以利用Session存储在服务器端,存储在服务器端的信息更加安全。

Session可以存储在服务器上的文件、数据库或者内存中。也可以将Session存储在Redis这种内存型数据库中,效率会更高。

使用Session维护用户登录状态的过程如下:

  • 用户进行登录时,用户提交包含用户名和密码的表单,放入HTTP请求报文中;
  • 服务器验证该用户名和密码,如果正确则把用户信息存储到Redis中,它在Redis中的key称为SessionID;
  • 服务器返回的响应报文的Set-Cookie首部字段包含了这个SessionID,客户端收到响应报文后将该Cookie值存入浏览器中;
  • 客户端之后对同一个服务器进行请求时会包含该Cookie值,服务器收到之后提取出SessionID,从Redis中取出用户信息,继续之前的业务操作。

应该注意SessionID的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的SessionID值。此外,还需要经常重新生成SessionID。在对安全性要求极高的场景下,例如转账等操作,除了使用Session管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证等方式。

浏览器禁用Cookie

此时无法使用Cookie来保存用户信息,只能使用Session。除此之外,不能再将SessionID存放到Cookie中,而是使用URL重写技术,将SessionID作为URL的参数进行传递。

Cookie和Session选择

  • Cookie只能存储ASCII码字符串,而Session可以存储任何类型的数据,因此在考虑数据复杂性时首选Session;
  • Cookie存储在浏览器中,容易被恶意查看。如果非要将一些隐私数据存在Cookie中,则可以将Cookie值进行加密,然后在服务器进行解密。
  • 对于大型网站,如果用户所有的信息都存储在Session中,那么开销是非常大的,因此不建议将所有的用户信息都存储到Session中。

HTTPS

HTTP有以下安全性问题:

  • 使用明文进行通信,内容可能会被窃听;
  • 不验证通信方的身份,通信方的身份有可能遭遇伪装;
  • 无法证明报文的完整性,报文有可能遭篡改。

HTTPS并不是新的协议,而是让HTTP先和SSL通信,再由SSL和TCP通信,也就是说HTTPS使用了隧道进行通信。

通过使用SSL,HTTPS具有了加密(防窃听)、认证(防伪装)和完整性保护(防篡改)。

加密

对称密钥加密

对称密钥加密,加密和解密使用同一密钥。

  • 优点:运算速度快;
  • 缺点:无法安全地将密钥传输给通信方。

非对称密钥加密

非对称密钥加密,又称公开密钥加密,加密和解密使用不同的密钥。

公开密钥所有人都可以获得,通信发送方获得接收方的公开密钥之后,就可以使用公开使用公开密钥进行加密,接收方收到通信内容后使用私有密钥解密。

非对称密钥除了用来加密,还可以用来进行签名。因为私有密钥无法被其他人获取,因此通信发送方使用其私有密钥进行签名,通信接收方使用发送发的公开密钥对签名进行解密,就能判断这个签名是否正确。

  • 优点:可以更安全地将公开密钥传输给通信发送方;
  • 缺点:运算速度慢。

HTTPS采用的加密方式

上面提到对称密钥加密方式的传输效率更高,但是无法安全地将密钥传输给通信方。而非对称加密方式可以保证传输的安全性,因此我们可以利用非对称密钥加密方式将传输给通信方。HTTPS采用混合的加密机制,正是利用了上面提到的方案:

  • 使用非对称密钥加密方式,传输对称密钥加密方式所需要的Secret Key,从而保证安全性;
  • 获得到Secret Key后,再使用对称密钥加密方式进行通信,从而保证效率。

认证

通过使用证书来对通信方进行认证。

数字证书认证机构(CA)是客户端与服务器双方都可信赖的第三方机构。

服务器的运营人员向CA提出公开密钥的申请,CA在判明提出申请者的身份之后,会对已申请的公开密钥做数字签名,然后分配这个已签名的公开密钥,并将公开密钥放入公开密钥证书后绑定在一起。

进行HTTPS通信时,服务器会把证书发送给客户端。客户端取得其中的公开密钥之后,先使用数字签名进行验证,如果验证通过,就可以开始通信了。

完整性保护

SSL提供报文摘要功能来进行完整性保护。

HTTP也提供了MD5报文摘要功能,但不是安全的。例如报文内容被篡改之后,同时重新计算MD5的值,通信接收方是无法意识到发生了篡改。

HTTPS的报文摘要功能之所以安全,是因为它结合了加密和认证这两个操作。是想一下,加密之后的报文,遭到篡改之后,也很难重新计算报文摘要,因为无法轻易获得明文。

HTTPS的缺点

  • 因为需要进行加密解密等过程,因此速度会更慢;
  • 需要支付证书授权的高额费用。

GET和POST比较

作用

GET 用于获取资源,而 POST 用于传输实体主体。

参数

GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看。

因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如 中文 会转换为 %E4%B8%AD%E6%96%87,而空格会转换为 %20。POST 参数支持标准字符集。

安全

安全的 HTTP 方法不会改变服务器状态,也就是说它只是可读的。

GET 方法是安全的,而 POST 却不是,因为 POST 的目的是传送实体主体内容,这个内容可能是用户上传的表单数据,上传成功之后,服务器可能把这个数据存储到数据库中,因此状态也就发生了改变。

安全的方法除了 GET 之外还有:HEAD、OPTIONS。

不安全的方法除了 POST 之外还有 PUT、DELETE。

幂等性

幂等的 HTTP 方法,同样的请求被执行一次与连续执行多次的效果是一样的,服务器的状态也是一样的。换句话说就是,幂等方法不应该具有副作用(统计用途除外)。

所有的安全方法也都是幂等的。

在正确实现的条件下,GET,HEAD,PUT 和 DELETE 等方法都是幂等的,而 POST 方法不是。

GET /pageX HTTP/1.1 是幂等的,连续调用多次,客户端接收到的结果都是一样的

POST /add_row HTTP/1.1 不是幂等的,如果调用多次,就会增加多行记录

DELETE /idX/delete HTTP/1.1 是幂等的,即使不同的请求接收到的状态码不一样

Donate comment here