目录
一、项目需求
本次要实现一个https代理服务器,使用浏览器时,配置代理服务器,通过我们编写的代理服务器实现上网。
二、相关知识点
1、http代理协议浏览器配置代理服务器后,访问网站时,会先向代理服务器发送一个CONNECT请求报文,通知代理服务器与目标网站建立连接。代理服务器与目标网站建立连接后,需要返回一个响应报文"HTTP/1.1 200 Connection Established\r\n\r\n",告诉浏览器已经建立连接。浏览器这时会向代理服务器发送请求报文。代理服务器负责转发就行。2、网络协议基础知识3、Go的内置http、net包http包帮助我们建立一个http服务器,接收并处理http请求。http包中定义了一个Server对象表示http服务器。最重要的两个属性:
Addr:表示监听的地址,ip地址+端口号Handle:表示http请求处理逻辑4、Go的内置net包使用net.Dial直接与tcp服务器建立连接。
三、实现原理
建立一个http服务器接收到Connect请求后,与目标网站建立tcp连接,获取到与浏览器的tcp连接,从http通信降级为tcp通信。使用与浏览器的tcp连接返回响应报文"HTTP/1.1 200 Connection Established\r\n\r\n"在与浏览器建立的tcp连接和与目标网站之间建立的连接转发消息。四、代码实现
项目地址:https://gitee.com/xueyuanlu30/go-example-project/tree/master/httpsProxymain.go
package main import ( "httpsProxy/handle" "net/http" ) func main() { server := &http.Server{Addr: "127.0.0.1:8090", Handler: &handle.HttpsHandle{}} server.ListenAndServe() }Handle.go
package handle import ( "fmt" "io" "net" "net/http" ) type HttpsHandle struct { } func (h *HttpsHandle) ServeHTTP(rw http.ResponseWriter, req *http.Request) { if req.Method == "CONNECT" { fmt.Print("Connect请求") } else { fmt.Println("异常") return } remote, err := net.Dial("tcp", req.URL.Host) if err != nil { fmt.Println("连接目标错误") return } hj, _ := rw.(http.Hijacker) client, _, err := hj.Hijack() if err != nil { fmt.Print("获取tcp连接错误") } var HTTP200 = []byte("HTTP/1.1 200 Connection Established\r\n\r\n") client.Write(HTTP200) go io.Copy(remote, client) go io.Copy(client, remote) }