golang实现正_反向代理服务

1 概念

1.1 正向代理

一种客户端代理技术,用于帮助客户端访问无法直接访问的网络资源,并隐藏客户端IP,常见的场景有***、浏览器HTTP代理

1.2 反向代理

一种服务端代理技术,用于隐藏真实服务端节点,并实现负载均衡、缓存、安全校验、协议转换等,常见的有LVS、nginx

2 实践

2.1 实现一个正向代理服务2.1.1 基本思路代理接收客户端请求,复制该请求对象,并根据实际需要配置请求参数构造新的请求,发送到服务端,并获取服务端的响应内容接收到响应内容后返回给客户端2.1.2 具体实现package main import ( "fmt" "io" "log" "net" "net/http" "strings" ) type proxy struct {} func (p *proxy)ServeHTTP(w http.ResponseWriter,r *http.Request){ fmt.Printf("Received request: %s %s %s\n",r.Method,r.Host,r.RemoteAddr) transport := http.DefaultTransport // 浅拷贝一个request 对象,避免后续修影响了源对象 req := new(http.Request) *req = *r // 设置X-Forward-For 头部 if clientIp,_,err := net.SplitHostPort(r.RemoteAddr);err ==nil{ if prior,ok := req.Header["X-Forward-For"];ok{ clientIp = strings.Join(prior,", ") + ", " + clientIp } req.Header.Set("X-Forward-For",clientIp) } // 构造新请求 response,err:=transport.RoundTrip(req) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } // 获取响应数据并返回 for k,v := range response.Header{ for _,v1 := range v{ w.Header().Add(k,v1) } } w.WriteHeader(response.StatusCode) io.Copy(w,response.Body) response.Body.Close() } func main() { //mux := http.NewServeMux() server := &http.Server{ Addr: ":9090", Handler: &proxy{}, } if err:=server.ListenAndServe();err != nil{ log.Fatal("Http proxy server start failed.") } } 2.2 Go实现一个反向代理服务2.2.1 基本思路2.2.2 具体实现

Http real Server 实现:监听8081和8082端口,返回请求的URL

package main import ( "fmt" "log" "net/http" "os" "os/signal" "syscall" "time" ) type realServer struct { Addr string } func (rs *realServer) HelloHandler(w http.ResponseWriter,r *http.Request){ reqUrl := fmt.Sprintf("http://%s%s\n",rs.Addr,r.RequestURI) w.Write([]byte(reqUrl)) } func (rs *realServer) Run(){ fmt.Println("Http server tart to serve at :",rs.Addr) mux := http.NewServeMux() mux.HandleFunc("/",rs.HelloHandler) server := &http.Server{ Addr: rs.Addr, Handler: mux, WriteTimeout: time.Second * 3, } go func(){ if err := server.ListenAndServe();err != nil{ log.Fatal("Start http server failed,err:",err) } }() } func main() { rs1 := &realServer{Addr:"127.0.0.1:8081"} rs2 := &realServer{Addr:"127.0.0.1:8082"} go rs1.Run() go rs2.Run() doneCh := make(chan os.Signal) signal.Notify(doneCh,syscall.SIGINT,syscall.SIGTERM) <- doneCh }

模拟请求

// output $ curl http://127.0.0.1:8081/hellotest?id=1 -s http://127.0.0.1:8081/hellotest?id=1 $ curl http://127.0.0.1:8082/hellotest?id=2 -s http://127.0.0.1:8082/hellotest?id=2

反向代理服务端实现

package main import ( "bufio" "fmt" "log" "net/http" "net/url" "time" ) var serverPort = "8888" // 为了测试,简单的通过当前时间戳取余的方式模拟随机访问后端rs func GetRandServer()string{ ports := []string{"8081","8082"} n := time.Now().Unix() % 2 return ports[n] } func handler(w http.ResponseWriter,r *http.Request){ // 解析并修改代理服务 port := GetRandServer() proxyAddr := ":" + port proxy ,err := url.Parse(proxyAddr) if err != nil{ log.Println(err) return } r.URL.Scheme = proxy.Scheme r.URL.Host = proxy.Host // 代理请求 transport := http.DefaultTransport resp ,err := transport.RoundTrip(r) if err != nil{ log.Println(err) w.WriteHeader(http.StatusInternalServerError) return } // 将响应结果返回 for key,value := range resp.Header{ for _,v := range value{ w.Header().Add(key,v) } } defer resp.Body.Close() bufio.NewReader(resp.Body).WriteTo(w) } func main() { http.HandleFunc("/",handler) fmt.Println("Http reverse proxy server start at : 127.0.0.1:",serverPort) if err := http.ListenAndServe(":"+serverPort,nil);err != nil{ log.Fatal("Start server failed,err:",err) } }

测试

$ for i in {0..9};do curl http://127.0.0.1:8888/reversetest?id=111 -s;done http://127.0.0.1:8082/reversetest?id=111 http://127.0.0.1:8082/reversetest?id=111 http://127.0.0.1:8082/reversetest?id=111 http://127.0.0.1:8082/reversetest?id=111 http://127.0.0.1:8081/reversetest?id=111 http://127.0.0.1:8081/reversetest?id=111 http://127.0.0.1:8081/reversetest?id=111 http://127.0.0.1:8081/reversetest?id=111 http://127.0.0.1:8081/reversetest?id=111 http://127.0.0.1:8082/reversetest?id=111

go语言中文文档:www.topgoer.com

本文转自: