一个简单的Golang实现的HTTPProxy方法

⼀个简单的Golang实现的HTTPProxy⽅法
最近因为换了Mac,以前的Linux基本上不再使⽤了,但是我的SS代理还得⽤。SS代理⼤家都了解,⼀个很NB的socks代理⼯具,但是就是因为他是Socks的,想⽤HTTP代理的时候很不⽅便。
以前在Linux下的时候,会安装⼀个Privoxy把socks代理转换为HTTP代理,开机启动,也⽐较⽅便。但是Mac下使⽤Brew安装的Privoxy就很难⽤,再加上以前⼀个有个想法,⼀个软件搞定socks和HTTP代理,这样就不⽤安装⼀个单独的软件做转换了。
想着就开始做吧,以前基本上没有搞过太多的⽹络编程,最近也正好在研究Go,正好练练⼿。
我们这⾥主要讲使⽤HTTP/1.1协议中的CONNECT⽅法建⽴起来的隧道连接,实现的HTTP Proxy。这种代理的好处就是不⽤知道客户端请求的数据,只需要原封不动的转发就可以了,对于处理HTTPS的请求就⾮常⽅便了,不⽤解析他的内容,就可以实现代理。
启动代理监听
要想做⼀个HTTP Proxy,我们需要启动⼀个服务器,监听⼀个端⼝,⽤于接收客户端的请求。Golang给我们提供了强⼤的net包供我们使⽤,我们启动⼀个代理服务器监听⾮常⽅便。
l, err := net.Listen("tcp", ":8080")
if err != nil {
log.Panic(err)
}
以上代理我们就实现了⼀个在8080端⼝上监听的服务器,我们这⾥没有写ip地址,默认在所有ip地址上进⾏监听。如果你只想本机适⽤,可以使⽤127.0.0.1:8080,这样机器就访问不了你的代理服务器了。
监听接收代理请求
定西日报电子版启动了代理服务器,就可以开始接受不了代理请求了,有了请求,我们才能做进⼀步的处理。
for {
client, err := l.Accept()
if err != nil {
log.Panic(err)
}
go handleClientRequest(client)
}
Listener接⼝的Accept⽅法,会接受客户端发来的连接数据,这是⼀个阻塞型的⽅法,如果客户端没有连接数据发来,他就是阻塞等待。接收来的连接数据,会马上交给handleClientRequest⽅法进⾏处理,这⾥使⽤⼀个go关键字开⼀个goroutine的⽬的是不阻塞客户端的接收,代理服务器可以马上接收下⼀个连接请求。
解析请求,获取要访问的IP和端⼝
有了客户端的代理请求了,我们还得从请求⾥提取客户端要访问的远程主机的IP和端⼝,这样我们的代理服务器才可以建⽴和远程主机的连接,代理转发。
HTTP协议的头信息⾥就包含有我们需要的主机名(IP)和端⼝信息,并且是明⽂的,协议很规范,类似于:
le:443 HTTP/1.1
Host: le:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
可以看到我们需要的在第⼀⾏,第⼀个⾏的信息以空格分开,第⼀部分CONNECT是请求⽅法,这⾥是CONNECT,除此之外还有GET,POST等,都是HTTP协议的标准⽅法。
第⼆部分是URL,https的请求只有host和port,http的请求是⼀个完成的url,等下会看个样例,就明⽩了。
第三部是HTTP的协议和版本,这个我们不⽤太关注。
以上是⼀个https的请求,我们看下http的:陆征祥
GET / HTTP/1.1
Host:
Proxy-Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36
有了分析,下⾯我们就可以从HTTP头信息中获取请求的url和method信息了。
var b [1024]byte
n, err := client.Read(b[:])
if err != nil {
log.Println(err)
return
}
var method, host, address string
fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)
hostPortURL, err := url.Parse(host)
if err != nil {
log.Println(err)
return
}
然后需要进⼀步对url进⾏解析,获取我们需要的远程服务器信息
if hostPortURL.Opaque == "443" { //https访问
address = hostPortURL.Scheme + ":443"
} else { //http访问
if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端⼝,默认80
数理统计法address = hostPortURL.Host + ":80"
} else {
address = hostPortURL.Host
}
}
这样就完整了获取了要请求服务器的信息,他们可能是以下⼏种格式
ip:port
hostname:port
domainname:port
就是有可能是ip(v4orv6),有可能是主机名(内⽹),有可能是域名(dns解析)
代理服务器和远程服务器建⽴连接
有了远程服务器的信息了,就可以进⾏拨号建⽴连接了,有了连接,才可以通信。
//获得了请求的host和port,就开始拨号吧
server, err := net.Dial("tcp", address)
if err != nil {
log.Println(err)
return
澜沧江大桥
}
数据转发
拨号成功后,就可以进⾏数据代理传输了
if method == "CONNECT" {
fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")
} else {
server.Write(b[:n])
}
//进⾏转发
go io.Copy(server, client)
io.Copy(client, server)
其中对CONNECT⽅法有单独的回应,客户端说要建⽴连接,代理服务器要回应建⽴好了,然后才可以像HTTP⼀样请求访问。
运⾏外国外VPS上
到这⾥,我们的代理服务器全部开发完成了,下⾯是完整的源代码:
package main
import (
"bytes"
"fmt"
"io"
"log"
缩水甘油"net"
"net/url"
"strings"
)
func main() {
log.SetFlags(log.LstdFlags|log.Lshortfile)
l, err := net.Listen("tcp", ":8081")
if err != nil {
log.Panic(err)
}
for {
client, err := l.Accept()
if err != nil {
log.Panic(err)
}
go handleClientRequest(client)
}
}
func handleClientRequest(client net.Conn) {
if client == nil {
return
}
defer client.Close()
var b [1024]byte
n, err := client.Read(b[:])
if err != nil {
log.Println(err)
return
}
var method, host, address string
fmt.Sscanf(string(b[:bytes.IndexByte(b[:], '\n')]), "%s%s", &method, &host)
hostPortURL, err := url.Parse(host)
if err != nil {
log.Println(err)
return
}
if hostPortURL.Opaque == "443" { //https访问
address = hostPortURL.Scheme + ":443"
} else { //http访问
if strings.Index(hostPortURL.Host, ":") == -1 { //host不带端⼝,默认80
address = hostPortURL.Host + ":80"
} else {
address = hostPortURL.Host
}
}
//获得了请求的host和port,就开始拨号吧
server, err := net.Dial("tcp", address)
if err != nil {
log.Println(err)
return
}
if method == "CONNECT" {
fmt.Fprint(client, "HTTP/1.1 200 Connection established\r\n")
} else {
多西环素server.Write(b[:n])
}
//进⾏转发
go io.Copy(server, client)
io.Copy(client, server)
}
把源代码编译,然后放到你国外的VPS上,在⾃⼰机器上配置好HTTP代理,就可以到处访问,⾃由⾃在了。
以上这篇⼀个简单的Golang实现的HTTP Proxy⽅法就是⼩编分享给⼤家的全部内容了,希望能给⼤家⼀个参考,也希望⼤家
多多⽀持。

本文发布于:2024-09-25 00:27:10,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/181801.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议