代理

所谓的“代理服务”就是指服务本身不生产内容,而是处于中间位置转发上下游的请求和响应,具有双重身份:面向下游的用户时,表现为服务器,代表源服务器响应客户端的请求;而面向上游的源服务器时,又表现为客户端,代表客户端发送请求。

由于代理处在 HTTP 通信过程的中间位置,相应地就对上屏蔽了真实客户端,对下屏蔽了真实服务器,简单的说就是“欺上瞒下”。在这个中间层的“小天地”里就可以做很多的事情,为 HTTP 协议增加更多的灵活性,实现客户端和服务器的“双赢”。
代理最基本的一个功能是负载均衡。因为在面向客户端时屏蔽了源服务器,客户端看到的只是代理服务器,源服务器究竟有多少台、是哪些 IP 地址都不知道。于是代理服务器就可以掌握请求分发的“大权”,决定由后面的哪台服务器来响应请求。

理中常用的负载均衡算法你应该也有所耳闻吧,比如轮询、一致性哈希等等,这些算法的目标都是尽量把外部的流量合理地分散到多台源服务器,提高系统的整体资源利用率和性能。

在负载均衡的同时,代理服务还可以执行更多的功能,比如:

  • 健康检查:使用“心跳”等机制监控后端服务器,发现有故障就及时“踢出”集群,保证服务高可用;
  • 安全防护:保护被代理的后端服务器,限制 IP 地址或流量,抵御网络攻击和过载;
  • 加密卸载:对外网使用 SSL/TLS 加密通信认证,而在安全的内网不加密,消除加解密成本;
  • 数据过滤:拦截上下行的数据,任意指定策略修改请求或者响应;
  • 内容缓存:暂存、复用服务器响应

代理相关头字段

代理服务器需要用字段“Via”标明代理的身份
image.png

如果想要知道客户端的真实 IP 地址,可以使用字段“X-Forwarded-For”和“X-Real-IP”

  • X-Forwarded-For”的字面意思是“为谁而转发”,形式上和“Via”差不多,也是每经过一个代理节点就会在字段里追加一个信息。但“Via”追加的是代理主机名(或者域名),而“X-Forwarded-For”追加的是请求方的 IP 地址。所以,在字段里最左边的 IP 地址就客户端的地址。

  • X-Real-IP”是另一种获取客户端真实 IP 的手段,它的作用很简单,就是记录客户端 IP 地址,没有中间的代理信息,相当于是“X-Forwarded-For”的简化版。如果客户端和源服务器之间只有一个代理,那么这两个字段的值就是相同的。

代理协议

  1. PROXY TCP4 1.1.1.1 2.2.2.2 55555 80\r\n
  2. GET / HTTP/1.1\r\n
  3. Host: www.xxx.com\r\n
  4. \r\n

服务器看到这样的报文,只要解析第一行就可以拿到客户端地址,不需要再去理会后面的 HTTP 数据,省了很多事情。

缓存代理

HTTP 的服务器缓存功能主要由代理服务器来实现(即缓存代理)
image.png

代理服务收到源服务器发来的响应数据后需要做两件事。第一个当然是把报文转发给客户端,而第二个就是把报文存入自己的 Cache 里。

在 HTTP 的缓存体系中,缓存代理的身份十分特殊,它“既是客户端,又是服务器”,同时也“既不是客户端,又不是服务器”。

源服务器的缓存控制

“Cache-Control”属性:max-age、no_store、no_cache 和 must-revalidate,
这 4 种缓存属性可以约束客户端,也可以约束代理。

首先,我们要区分客户端上的缓存和代理上的缓存,可以使用两个新属性“private”和“public”。

“private”表示缓存只能在客户端保存,是用户“私有”的,不能放在代理上与别人共享。而“public”的意思就是缓存完全开放,谁都可以存,谁都可以用。

缓存失效后的重新验证也要区分开(即使用条件请求“Last-modified”和“ETag”),“must-revalidate”是只要过期就必须回源服务器验证,而新的“proxy-revalidate”只要求代理的缓存过期后必须验证,客户端不必回源,只验证到代理这个环节就行了。

再次,缓存的生存时间可以使用新的“s-maxage”(s 是 share 的意思,注意 maxage 中间没有“-”),只限定在代理上能够存多久,而客户端仍然使用“max_age”。

还有一个代理专用的属性“no-transform”。代理有时候会对缓存下来的数据做一些优化,比如把图片生成 png、webp 等几种格式,方便今后的请求处理,而“no-transform”就会禁止这样做,不许“偷偷摸摸搞小动作”。
image.png源服务器在设置完“Cache-Control”后必须要为报文加上“Last-modified”或“ETag”字段。否则,客户端和代理后面就无法使用条件请求来验证缓存是否有效,也就不会有 304 缓存重定向。

客户端的缓存控制

image.png
关于缓存的生存时间,多了两个新属性“max-stale”和“min-fresh”。
“max-stale”的意思是如果代理上的缓存过期了也可以接受,但不能过期太多,超过 x 秒也会不要。“min-fresh”的意思是缓存必须有效,而且必须在 x 秒后依然有效。

有的时候客户端还会发出一个特别的“only-if-cached”属性,表示只接受代理缓存的数据,不接受源服务器的响应。如果代理上没有缓存或者缓存过期,就应该给客户端返回一个 504(Gateway Timeout)。