Golang代理实现 | Go主题月

1,463 阅读1分钟

正向代理

正向代理是一种客户端代理技术,帮助客户端访问无法访问的服务资源,可以隐藏用户真实IP。比如:浏览器web代理,VPN等

反向代理

反向代理是一种服务端的代理技术,帮助服务器做负载均衡,缓存,提供安全校验等,可以隐藏服务器真实IP。比如:LVS技术,nginx proxy_pass等

Golang实现正向代理

  • 代理接收客户端的请求,复制原请求对象,并根据数据配置型请求各种参数
  • 把新请求发送到真实服务端,并接收到服务器端返回
  • 代理服务器对相应做一些处理,然后返回给客户端
package main

import (
	"fmt"
	"io"
	"net"
	"net/http"
	"strings"
)

type Pxy struct{}

func (p *Pxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
	fmt.Printf("Received request %s %s %s\n", req.Method, req.Host, req.RemoteAddr)
	transport := http.DefaultTransport
	// step 1,浅拷贝对象,然后就再新增属性数据
	outReq := new(http.Request)
	*outReq = *req
	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
		if prior, ok := outReq.Header["X-Forwarded-For"]; ok {
			clientIP = strings.Join(prior, ", ") + ", " + clientIP
		}
		outReq.Header.Set("X-Forwarded-For", clientIP)
	}
	
	// step 2, 请求下游
	res, err := transport.RoundTrip(outReq)
	if err != nil {
		rw.WriteHeader(http.StatusBadGateway)
		return
	}

	// step 3, 把下游请求内容返回给上游
	for key, value := range res.Header {
		for _, v := range value {
			rw.Header().Add(key, v)
		}
	}
	rw.WriteHeader(res.StatusCode)
	io.Copy(rw, res.Body)
	res.Body.Close()
}

func main() {
	fmt.Println("Serve on :8080")
	http.Handle("/", &Pxy{})
	http.ListenAndServe("0.0.0.0:8080", nil)
}

Golang实现反向代理

package main

import (
	"bufio"
	"log"
	"net/http"
	"net/url"
)

var proxy_addr = "http://127.0.0.1:2003"

var port = "2002"

func main() {
	http.HandleFunc("/", handler)
	log.Println("start Serving on port" + port)
	err := http.ListenAndServe(":"+port, nil)
	if err != nil {
		log.Fatal(err)
	}
}

func handler(w http.ResponseWriter, r *http.Request) {
	//1 解析代理地址 并更改请求体的协议和主机
	proxy, err := url.Parse(proxy_addr)
	r.URL.Scheme = proxy.Scheme
	r.URL.Host = proxy.Host

	//2 请求下游
	transport := http.DefaultTransport
	resp, err := transport.RoundTrip(r)
	if err != nil {
		panic(err)
	}

	//3 把下游请求内容返回给上游
	for k, vv := range resp.Header {
		for _, v := range vv {
			w.Header().Add(k, v)
		}
	}
	defer resp.Body.Close()
	bufio.NewReader(resp.Body).WriteTo(w)
}