Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP 代理 #37

Open
18888628835 opened this issue Jun 1, 2021 · 0 comments
Open

HTTP 代理 #37

18888628835 opened this issue Jun 1, 2021 · 0 comments

Comments

@18888628835
Copy link
Owner

18888628835 commented Jun 1, 2021

HTTP 代理

HTTP 采用了请求-应答的模式,也就是都说起码会有两方互相协商,在前面的章节说过,我们的 HTTP 中间还可以夹杂各种代理,相当于中间商,这就是 HTTP 代理。

image.png

在这一层级链中,起点是浏览器,中间的角色被称为代理服务器,终点则是源服务器。

代理服务本身不产生任何数据内容,而只是作为中间位置转发上下游的请求和响应,也就是说,它既可以是信息的请求方,也可以是信息的响应方。

代理的作用

在简单的请求-应答模式下,为什么要加上一层代理,它有什么作用呢?

代理最基本的功能是负载均衡,所谓负载均衡,就是代理服务器掌握请求分发,将不同的请求流量尽可能地分散发送给不同的源服务器,尽量避免源服务器压力过大,提高整体资源利用率。

image.png

在做负载均衡的同时,中间的代理还可以做更多的功能:

  • 安全防护:抵御网络攻击或过载
  • 加密:通过 SSL/TLS加密通信认证
  • 数据过滤:拦截上下行数据
  • 内容缓存:暂存复用服务器的响应

代理相关头部字段

代理服务器使用字段 Via标明代理的身份。

Via 是一个通用字段,在响应或者请求都可以使用。每当报文经过一个代理节点,代理服务器就会把自身的信息追加到字段的末尾。

如果通信链路中有很多个代理,就会在 Via 里形成一个链表,这样就可以知道报文究竟走过了多少个环节才到达目的地。

image

图中有两个代理:proxy1proxy2,客户端发送请求会经过这两个代理,依次添加就是 Via: proxy1, proxy2 ,等到服务器返回响应报文的时候就要反过来走,头字段就是 Via: proxy2, proxy1

Via 字段只解决了 客户端和源服务器判断是否存在代理的问题,还不能知道对方的真实信息。

但服务器的 IP 地址应该是保密的,关系到企业的内网安全,所以一般不会让客户端知道。不过反过来,通常服务器需要知道客户端的真实 IP 地址,方便做访问控制、用户画像、统计分析 。

可惜的是 HTTP 标准里并没有为此定义头字段 ,但已经出现了很多 事实上的标准 ,最常用的两个头字段是 X-Forwarded-For 和 X-Real-IP 。

  • X-Forwarded-For:链式存储

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

  • X-Real-IP:只有客户端 IP 地址

是另一种获取客户端真实 IP 的手段,它的作用很简单,就是记录客户端 IP 地址,没有中间的代理信息。

如果客户端和源服务器之间只有一个代理,那么这两个字段的值就是相同的。

image.png

代理协议

有了 X-Forwarded-For 等头字段,源服务器就可以拿到准确的客户端信息了。但对于代理服务器来说它并不是一个最佳的解决方案。

因为通过 X-Forwarded-For 操作代理信息 必须要解析 HTTP 报文头 ,这对于代理来说成本比较高,原本只需要简单地转发消息就好,而现在却必须要费力解析数据再修改数据,会降低代理的转发性能 。

另一个问题是 X-Forwarded-For 等头 必须要修改原始报文 ,而有些情况下是不允许甚至不可能的(比如使用 HTTPS 通信被加密 )。

所以就出现了一个专门的 代理协议 (The PROXY protocol) ,它由知名的代理软件 HAProxy 所定义,是一个 事实标准 ,被广泛采用(注意并不是 RFC)。

代理协议有 v1 和 v2 两个版本,v1 和 HTTP 差不多,也是明文,而 v2 是二进制格式。今天只介绍比较好理解的 v1,它在 HTTP 报文前增加了一行 ASCII 码文本,相当于又多了一个头。

这一行文本其实非常简单,开头必须是 PROXY 五个大写字母,然后是 TCP4 或者 TCP6 ,表示客户端的 IP 地址类型,再后面是请求方地址、应答方地址、请求方端口号、应答方端口号,最后用一个回车换行(\r\n)结束。

例如下面的这个例子,在 GET 请求行前多出了 PROXY 信息行,客户端的真实 IP 地址是 1.1.1.1 ,应答方地址是2.2.2.2,端口号是 55555。

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

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

不过代理协议并不支持 X-Forwarded-For 的链式地址形式,所以拿到客户端地址后再如何处理就需要代理服务器与后端自行约定。

小结

  • HTTP 代理就是客户端和服务器通信链路中的一个中间环节,为两端提供 代理服务
  • 代理处于中间层,为 HTTP 处理增加了更多的灵活性,可以实现负载均衡、安全防护、数据过滤等功能
  • 代理服务器需要使用字段 Via 标记自己的身份,多个代理会形成一个列表
  • 如果想要知道客户端的真实 IP 地址,可以使用字段 X-Forwarded-For 和 X-Real-IP
  • 专门的 代理协议 可以在不改动原始报文的情况下传递客户端的真实 IP
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant