一種客戶端代理技術,用於幫助客戶端訪問沒法直接訪問的網絡資源,並隱藏客戶端IP,常見的場景有***、瀏覽器HTTP代理nginx
一種服務端代理技術,用於隱藏真實服務端節點,並實現負載均衡、緩存、安全校驗、協議轉換等,常見的有LVS、nginx後端
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.") } }
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 := "http://127.0.0.1:" + 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