HTTP proxy 简单分析

656 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天,点击查看活动详情

反向代理 Reverse Proxy

一提起proxy这个词,对于熟悉nginx的人来说,那肯定是指反向代理。

反向代理,简单的说:

代理服务器收到http请求之后,根据http请求中的一些信息和提前准备好的配置,去将这个请求转发给真正的源。

然后将真正的源的回复,转发给客户端。

反向代理有几个关键点需要注意:

    1. 需要提前配置, 比如,nginx里需要配置 upstream
    1. 代理程序可以根据很多参数来判断,我到底进入哪个 upstream, 比如 Host、Path、要是愿意,甚至可以通过cookie,等,这个完全看代理程序怎么写。

反向代理就简单介绍到这里。

正向代理的概念

正向代理其实在开发过程中用的更多,比如说:

  • 抓包分析
  • 加快第三方库的获取
  • 等等

他的作用是什么呢,比如说你要访问 http://www.xxx.com, 由于你的网络有问题,你访问不了,你需要让一个能访问这个网址的人帮你访问,然后把Response回复给你,此时,这个能帮你访问的中间人,称之为正向代理

所以这个中间人,能抓包分析。

如果这个中间人比你的网络好,那么自然能加快整个过程。

正向代理 http 协议

一般来说,客户端和代理服务器之间,需要有一些提前的交流,比如说告知,我想访问的真正的源是什么。

那么 正向http代理,有这个过程吗?

我们不妨来试试.

环境准备

  • mac 或者 linux 命令行环境
  • windows 下,可以安装 msys2 或者 gitbash 来模拟 linux命令行
  • 需要安装两个命令: curlnc

无代理访问 http://www.baidu.com

输入如下指令:

$ curl -v http://www.baidu.com

我们可以看见整个过程, 这里我们把请求的部分拉出来:

*   Trying 14.215.177.38...
* TCP_NODELAY set
* Connected to www.baidu.com (14.215.177.38) port 80 (#0)
> GET / HTTP/1.1
> Host: www.baidu.com
> User-Agent: curl/7.64.1
> Accept: */*
>

我们可以看见,不使用代理的情况下,他直接访问了www.baidu.com的IP地址:14.215.177.38

有代理访问 http://www.baidu.com

那么如何让curl通过一个中间代理去访问指定的网址呢?

简单如斯:

$ http_proxy="http://127.0.0.1:8888" curl -v http://www.baidu.com

按回车,不出所料的话:

* About to connect() to proxy 127.0.0.1 port 8888 (#0)
*   Trying 127.0.0.1...
* 拒绝连接
* Failed connect to 127.0.0.1:8888; 拒绝连接
* Closing connection 0
curl: (7) Failed connect to 127.0.0.1:8888; 拒绝连接

从这段文字,可以看出,curl 试图访问 127.0.0.1:8888, 这正是我们想要的。

但是,我们并没有一个可用的代理程序监听 127.0.0.1:8888

此时,nc 命令派上用场:

新开一个窗口:

$ nc -l 8888 # 注意这个命令会卡在这里

这个命令的作用就是监听 127.0.0.1:8888 ,然后卡在这里,等到有人往里面发数据,就会打印。

然后在老窗口里:

$ http_proxy="http://127.0.0.1:8888" curl -v http://www.baidu.com

按下回车,我们可以看见,两个窗口都有动静。

我们先来看curl

* About to connect() to proxy 127.0.0.1 port 8888 (#0)
*   Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 8888 (#0)
> GET http://www.baidu.com/ HTTP/1.1
> User-Agent: curl/7.29.0
> Host: www.baidu.com
> Accept: */*
> Proxy-Connection: Keep-Alive

这个输出说明,他访问了127.0.0.1:8888, 然后将HTTP的一些 header(头) 发送了过去。

然后再来看看nc:

GET http://www.baidu.com/ HTTP/1.1
User-Agent: curl/7.29.0
Host: www.baidu.com
Accept: */*
Proxy-Connection: Keep-Alive

我们发现nc收到的报文就是一个普通的http报文,并没有其他的东西,也就是说:

在正向代理http协议的时候,并不需要多余的协商过程。

那问题就来了,一个真正的代理程序,是如何得知,要把这个请求转发给谁呢?

答案就在上面:

Host: www.baidu.com

这个 http 头就告知了代理程序,真正想访问的是 www.baidu.com

然后,代理程序通过解析这个 Host 头,就能把请求转发出去了。

正向代理 https 协议

通过刚才访问 http://www.baidu.com的过程,我们得知:

正向代理的时候,真正的源信息,是通过解析http报文来得知的。

但是问题来了,如果是 https 协议呢?

https协议的报文是加密的,那么中间人获取的就是一堆密文,也就无法解析 http Host 头部。

我们还是来观察一下:

第一个窗口,打开nc

$ nc -l 8888

第二个窗口,让 curl 用代理访问 https://www.baidu.com

 https_proxy="http://127.0.0.1:8888" curl -v https://www.baidu.com

注意,此时写在前面的环境变量是https_proxy

回车之后,观察 nc

CONNECT www.baidu.com:443 HTTP/1.1
Host: www.baidu.com:443
User-Agent: curl/7.29.0
Proxy-Connection: Keep-Alive

看见了没,这一段信息,是由curl发来的,但这不属于正常的https流程

这一段信息,说明:

curl在用代理请求https的时候,会先把必须的信息发给这个代理程序,比如说第一行:

CONNECT www.baidu.com:443

此时,代理程序,就知道了真正的源是:www.baidu.com:443, 从而进行后续的转发。