0%

HTTP-应用

HTTP相关的应用

HTTP具体应用

连接管理

短连接与长连接

image-20210520163234892

当浏览器访问一个包含多张图片的 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 是一些数据, 存储于你电脑上的文本文件中。当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。

Cookie 的作用就是用于解决 "如何记录客户端的用户信息"。由于之后每次请求都会需要携带 Cookie 数据,因此会带来额外的性能开销(尤其是在移动环境下)。现在随着现代浏览器开始支持各种各样的存储方式,Cookie 渐渐被淘汰。新的浏览器 API 已经允许开发者直接将数据存储到本地,如使用 Web storage API(本地存储和会话存储)或 IndexedDB。

用途

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

创建过程

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

1
2
3
4
5
6
HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: yummy_cookie=choco
Set-Cookie: tasty_cookie=strawberry

[page content]

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

1
2
3
GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: yummy_cookie=choco; tasty_cookie=strawberry

分类

  • 会话期 Cookie:浏览器关闭之后它会被自动删除,也就是说它仅在会话期内有效。

  • 持久性 Cookie:指定过期时间(Expires)或有效期(max-age)之后就成为了持久性的 Cookie。

1
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;

作用域

JavaScript

HttpOnly

标记为 HttpOnly 的 Cookie 不能被 JavaScript 脚本调用。跨站脚本攻击 (XSS) 常常使用 JavaScript 的 document.cookie API 窃取用户的 Cookie 信息,因此使用 HttpOnly 标记可以在一定程度上避免 XSS 攻击。

1
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly

Secure

标记为 Secure 的 Cookie 只能通过被 HTTPS 协议加密过的请求发送给服务端。但即便设置了 Secure 标记,敏感信息也不应该通过 Cookie 传输,因为 Cookie 有其固有的不安全性,Secure 标记也无法提供确实的安全保障。

Session

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

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

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

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

浏览器禁用Cookie

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

Cookie与Session选择

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

缓存

优点

  • 缓解服务器压力;
  • 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存

实现方法

  • 让代理服务器进行缓存;
  • 让客户端浏览器进行缓存

Cache-Control

HTTP/1.1 通过 Cache-Control 首部字段来控制缓存。

禁止进行缓存:no-store 指令规定不能对请求或响应的任何一部分进行缓存。

1
Cache-Control: no-store

强制确认缓存:no-cache 指令规定缓存服务器需要先向源服务器验证缓存资源的有效性,只有当缓存资源有效时才能使用该缓存对客户端的请求进行响应。

1
Cache-Control: no-cache

私有缓存和公共缓存:private 指令规定了将资源作为私有缓存,只能被单独用户使用,一般存储在用户浏览器中。public 指令规定了将资源作为公共缓存,可以被多个用户使用,一般存储在代理服务器中。

1
2
Cache-Control: private
Cache-Control: public

缓存过期机制:Expires 首部字段也可以用于告知缓存服务器该资源什么时候会过期。

  • max-age 指令出现在请求报文,并且缓存资源的缓存时间小于该指令指定的时间,那么就能接受该缓存。
  • max-age 指令出现在响应报文,表示缓存资源在缓存服务器中保存的时间。
1
2
3
Cache-Control: max-age=31536000

Expires: Wed, 04 Jul 2012 08:26:05 GMT
  • 在 HTTP/1.1 中,会优先处理 max-age 指令;
  • 在 HTTP/1.0 中,max-age 指令会被忽略掉。

缓存验证

需要先了解 ETag 首部字段的含义,它是资源的唯一标识。URL 不能唯一表示资源,例如 http://www.google.com/ 有中文和英文两个资源,只有 ETag 才能对这两个资源进行唯一标识。

1
ETag: "82e22293907ce725faf67773957acd12"

可以将缓存资源的 ETag 值放入 If-None-Match 首部,服务器收到该请求后,判断缓存资源的 ETag 值和资源的最新 ETag 值是否一致,如果一致则表示缓存资源有效,返回 304 Not Modified。

1
If-None-Match: "82e22293907ce725faf67773957acd12"

Last-Modified 首部字段也可以用于缓存验证,它包含在源服务器发送的响应报文中,指示源服务器对资源的最后修改时间。但是它是一种弱校验器,因为只能精确到一秒,所以它通常作为 ETag 的备用方案。如果响应首部字段里含有这个信息,客户端可以在后续的请求中带上 If-Modified-Since 来验证缓存。服务器只在所请求的资源在给定的日期时间之后对内容进行过修改的情况下才会将资源返回,状态码为 200 OK。如果请求的资源从那时起未经修改,那么返回一个不带有实体主体的 304 Not Modified 响应报文。

1
2
3
Last-Modified: Wed, 21 Oct 2015 07:28:00 GMT

If-Modified-Since: Wed, 21 Oct 2015 07:28:00 GMT

通信数据转发

代理

代理服务器接受客户端的请求,并且转发给其它服务器。使用代理的主要目的是:

  • 缓存
  • 负载均衡
  • 网络访问控制
  • 访问日志记录

代理服务器分为正向代理和反向代理两种:

  • 用户察觉得到正向代理的存在
  • 而反向代理一般位于内部网络中,用户察觉不到
image-20210520170133457

网关

与代理服务器不同的是,网关服务器会将 HTTP 转化为其它协议进行通信,从而请求其它非 HTTP 服务器的服务

隧道

使用 SSL 等加密手段,在客户端和服务器之间建立一条安全的通信线路。