代理那些事

本文只涉及代理的一些技术性原理和术语解释。

我在工作中经常用到代理:比如nginx的反向代理,使用littleproxy来作为程序可控的正向代理,公司内作为正向代理访问外网一些资料。

什么是代理

那么什么是代理,其实看下面的图,很简单,不需要用过多的文字来描述:

用户要访问app,因为各种原因直接不可达,那么在用户和app之间放一层代理:
1. 用户传入的请求流到代理
2. 代理将流转到目标app
3. app的响应流到代理
4. 代理将响应流转给用户
说白了,代理的作用就是你给我什么流,我转就是了。

那么假如让你来写一个代理软件,是不是很简单,只需要一个socket接收,另一个socket转发就可以了?理论上是这样的,比如HAPROXY就是这样的。但是实际上还是有很多地方需要考虑的,更多的是协议!

代理和协议转换

假如代理实现的是http/https的协议,那么用户传入的请求必须是http/https;假如代理实现的是mysql的协议,那么用户传入的请求必须是mysql协议;假如代理实现的是socks的协议,那么用户传入的请求必须是socks协议。

下面以socks代理服务器来举例说明:

等一下,有几个情况先看一下:
1. firefox中设置好了socks代理服务器后,居然能够使得socks代理http协议的流量?也就是说上面图中,发出http协议的请求,居然socks代理能够接受?原因是:firefox事先将http转换成了socks协议然后再发送,同理在响应的时候将socks协议转成了http协议了。
2. curl中,通过 --socks 来访问socks代理,那么curl的收发代码中肯定有对 http 互转 socks 的代码。
3. 在git中,我们可以设置如下来进行git的代理访问:

git config --global http.proxy 'socks5://127.0.0.1:1080'
git config --global https.proxy 'socks5://127.0.0.1:1080'

但是在git中,非常奇怪的能看到 http.proxy 中,居然可以设置 socks的协议。这个不像上2个情况,比如第1个firefox是对http和socks进行分别设置,然后由firefox来转换协议;第2个的curl通过--socks和-x来区分,由curl来转换协议。那么git怎么弄了个在 http 中设置成 socks 的协议呢?
这是因为只有HTTP_PROXY这种约定俗成的环境变量定义,而没有SOCKS_PROXY这个环境变量。git采用了一个取巧的办法(尽管我没有查git的源代码,但是根据原理肯定能猜出来),就是判断HTTP_PROXY的内容假如是socks协议的就转socks。

上面3个情况,都可以通过设置环境变量进行全局代理,详见HTTP_PROXY,HTTPS_PROXY,NO_PROXY,ALL_PROXY来自什么协议?

通过上面3个情况可以看到,对于 http互转socks这个过程,都是在客户端本身内部完成的,而和socks代理没有任何关系。

根据上面的理论,再来看一个现象,分析一下为什么会出现这样的情况:
minikube start
然后会去下载一些文件,因为一些原因下载不下来就会卡在那里,这个时候,假如用HTTP_PROXY=socks://127.0.0.1:1080,那么也还是下载不下来,为什么原因呢?因为minikube start会调用curl去下载文件,而curl不同于git,curl是http_proxy和socks是分开的。问题就出在这里。那怎么办呢?有几种解决办法:1,采用privoxy对http和socks进行互换;2,直接用nginx来作为http的代理,详见我的另一篇博文玩转nginx:用nginx搭建正向代理,支持http和https,当然假如就minikube这个来说,建议采用阿里修改的minikube,非常好用,阿里minikube

正向代理和认证

从我的那篇关于nginx代理的文章中知道,nginx或者tinyproxy从http的原理上来说,因为是短连接,所以天生对于认证不方便或者实现不了(注意,这里的认证不是说nginx带的安全认证,那个安全认证在代理中没有用,你总不可能让你所访问的网站上带上你的认证信息吧)。

所以,对于socks来说,在用户和代理之间再加一个代理客户端,这个代理客户端就是和代理进行长连接,当然也具有认证的功能。

反向代理和正向代理


反向代理:关键点是用户在外网,代理在内网。

正向代理:关键点是用户和代理都在内网中。