对go语言的反向代理还不是很熟悉,先把相关代码记录下来。
proxy.go
package main
import (
	"context"
	"errors"
	"fmt"
	"net"
	"net/http"
	"net/http/httputil"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)
type Transport struct {
	*http.Transport
	lastAccess atomic.Value
}
type HTTPProxyRoundTripper struct {
	transprots map[string]*Transport
	rwmutex sync.RWMutex
}
func newHTTPProxyRoundTripper() *HTTPProxyRoundTripper {
	rt := &HTTPProxyRoundTripper{
		transprots: make(map[string]*Transport),
	}
	return rt
}
func (rt *HTTPProxyRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
	clientTag := req.Header.Get("client_tag")
	if clientTag == "" {
		return nil, errors.New("no client tag src")
	}
	req.Header.Del("client_tag")
	rt.rwmutex.Lock()
	if transport, ok := rt.transprots[clientTag]; ok {
		rt.rwmutex.Unlock()
		return transport.RoundTrip(req)
	}
	transport := &Transport{
		Transport: rt.createNewTransport(),
	}
	rt.transprots[clientTag] = transport
	rt.rwmutex.Unlock()
	return transport.RoundTrip(req)
}
func (rt *HTTPProxyRoundTripper) createNewTransport() *http.Transport {
	netDialer := &net.Dialer{
		Timeout:   30 * time.Second,
		KeepAlive: 30 * time.Second,
	}
	dialer := func(ctx context.Context, network string, addr string) (net.Conn, error) {
		s, ok := ctx.Value("backaddrs").(string)
		if !ok {
			fmt.Println("no backend address find")
			return nil, errors.New("no backend address found")
		}
		serverAddrArr := strings.Split(s, ",")
		for _, addr := range serverAddrArr {
			addr := strings.TrimSpace(addr)
			conn, err := netDialer.DialContext(ctx, network, addr)
			if err == nil {
				fmt.Println("connect to backend server success, addr is ", addr)
				return conn, nil
			}
			select {
			case <-ctx.Done():
				break
			default:
			}
		}
		fmt.Println("connetc to backend server failed, address: %v", s)
		return nil, fmt.Errorf("connect to backend server failed. addrs:%v", s)
	}
	transport := &http.Transport{
		Proxy:        nil,
		DialContext:  dialer,
		MaxIdleConns: 100,
	}
	return transport
}
type HTTPProxy struct {
	rp *httputil.ReverseProxy
}
func NewHTTPProxy() *HTTPProxy {
	transport := newHTTPProxyRoundTripper()
	proxy := &HTTPProxy{
		rp: &httputil.ReverseProxy{
			Director: func(req *http.Request) {
			},
			Transport: transport,
		},
	}
	return proxy
}
func (proxy *HTTPProxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	serverAddrs := r.Header.Get("backaddrs")
	fmt.Println("url: ", r.URL)
	ctx := context.WithValue(r.Context(), "backaddrs", serverAddrs)
	r = r.WithContext(ctx)
	r.URL.Scheme = "http"
	r.URL.Host = r.Host
	fmt.Println("after url: ", r.URL)
	proxy.rp.ServeHTTP(w, r)
}
func main() {
	httpProxyHandler := NewHTTPProxy()
	server := &http.Server{
		Addr:    ":8000",
		Handler: httpProxyHandler,
	}
	server.ListenAndServe()
}
test_proxy.go
package main
import (
	"fmt"
	"io/ioutil"
	"net/http"
)
func main() {
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://127.0.0.1:8000/hello", nil)
	if err != nil {
		fmt.Println("new request failed, error is ", err)
		return
	}
	req.Header.Set("client_tag", "127.0.0.1")
	req.Header.Set("backaddrs", "127.0.0.1:8001")
	resp, err := client.Do(req)
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("read failed", err)
		return
	}
	fmt.Println(string(body))
}
 
版权声明:本文为qq_35728402原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
