最近因为换了Mac,以前的Linux基本上不再使用了,但是我的学生代理还得用s代理大家都了解,一个很NB的袜子代理工具,但是就是因为他是袜子的,想用HTTP代理的时候很不方便。

  

以前在Linux下的时候,会安装一个Privoxy把袜子代理转换为HTTP代理,开机启动,也比较方便。但是Mac下使用啤酒安装的Privoxy就很难用,再加上以前一个有个想法,一个软件搞定袜子和HTTP代理,这样就不用安装一个单独的软件做转换了。

  

想着就开始做吧,以前基本上没有搞过太多的网络编程,最近也正好在研究,正好练练手。

  

我们这里主要讲使用HTTP/1.1协议中连接的方法建立起来的隧道连接,实现的HTTP代理。这种代理的好处就是不用知道客户端请求的数据,只需要原封不动的转发就可以了,对于处理HTTPS的请求就非常方便的了,不用解析他的内容,就可以实现代理。

  

<>强启动代理监听

  

要想做一个HTTP代理,我们需要启动一个服务器,监听一个端口,用于接收客户端的请求.Golang给我们提供了强大的净包供我们使用,我们启动一个代理服务器监听非常方便。

        l,犯错:=净。听(“tcp”、“: 8080”)   如果犯错!=nil {   log.Panic (err)   }      

以上代理我们就实现了一个在8080年端口上监听的服务器,我们这里没有写ip地址,默认在所有ip地址上进行监听。如果你只想本机适用,可以使用127.0.0.1:8080,这样机器就访问不了你的代理服务器了。

  

<>强监听接收代理请求

  

启动了代理服务器,就可以开始接受不了代理请求了,有了请求,我们才能做进一步的处理。

        为{   客户端,犯错:=l.Accept ()   如果犯错!=nil {   log.Panic (err)   }      去handleClientRequest(客户端)   }   之前      

侦听器接口的接受方法,会接受客户端发来的连接数据,这是一个阻塞型的方法,如果客户端没有连接数据发来,他就是阻塞等待。接收来的连接数据,会马上交给handleClientRequest方法进行处理,这里使用一个去关键字开一个goroutine的目的是不阻塞客户端的接收,代理服务器可以马上接收下一个连接请求。

  

<>强解析请求,获取要访问的IP和端口

  

有了客户端的代理请求了,我们还得从请求里提取客户端要访问的远程主机的IP和端口,这样我们的代理服务器才可以建立和远程主机的连接,代理转发。

  

HTTP协议的头信息里就包含有我们需要的主机名(IP)和端口信息,并且是明文的,协议很规范,类似于:

        连接www.google.com: 443 HTTP/1.1   主持人:www.google.com: 443   Proxy-Connection:维生   用户代理:Mozilla/5.0(麦金塔电脑;Intel Mac OS X 10 _12_0) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/55.0.2883.95 Safari 537.36      

可以看到我们需要的在第一行,第一个行的信息以空格分开,第一部分连接是请求方法,这里是连接,除此之外还有得到,等,都是HTTP协议的标准方法。

  

第二部分是URL, https的请求只有主机和端口,http的请求是一个完成的URL,等下会看个样例,就明白了。

  

第三部是HTTP的协议和版本,这个我们不用太关注。

  

以上是一个https的请求,我们看下http的:

        得到http://www.flysnow.org/HTTP/1.1   主持人:www.flysnow.org   Proxy-Connection:维生   Upgrade-Insecure-Requests: 1   用户代理:Mozilla/5.0(麦金塔电脑;Intel Mac OS X 10 _12_0) AppleWebKit/537.36 (KHTML,像壁虎)Chrome/55.0.2883.95 Safari 537.36      

可以看到计画的,没有端口号(默认是80),比https多了schame-http://

。   

有了分析、下面我们就可以从HTTP头信息中获取请求的url和方法信息了。

           var b[1024]字节   n,犯错:=client.Read (b [:])   如果犯错!=nil {   log.Println (err)   返回   }   var方法、主机地址字符串   fmt.Sscanf (string (b[:字节。IndexByte (b [:], ' \ n '))),“% s % s”,和方法,及主机)   hostPortURL犯错:=url.Parse(主机)   如果犯错!=nil {   log.Println (err)   返回      }   之前      

然后需要进一步对url进行解析,获取我们需要的远程服务器信息

           如果hostPortURL。不透明的==" 443 " {//https访问   地址=hostPortURL。计划+“:443”   其他}{//http访问   如果strings.Index (hostPortURL。主机,“:”)==1{//主机不带端口,默认80   地址=hostPortURL。主机+“:80”   其他}{   地址=hostPortURL.Host   }   }