go 实现反向代理

正向代理和反向代理区别

正向代理
代理的是客户端,隐藏了客户端的真实IP,部署在客户端网络中,访问外部资源,例如通过代理访问外网。

反向代理
代理的是服务端,隐藏了服务端的真实IP,部署在服务端网络中,提供负载均衡,例如访问nginx。

实现反向代理

package main

import (
	"log"
	"net/http"
	"net/http/httputil"
	"net/url"
	"sync"
)

var targetURL *url.URL
// 避免重复分配内存,降低GC压力
var reverseProxyPool = &sync.Pool{
	New: func() any {
		proxy := httputil.NewSingleHostReverseProxy(targetURL)
		return proxy
	},
}

func main() {
	var err error
    // 解析目标服务器地址
    targetURL, err = url.Parse("http://www.baidu.com")
    if err != nil {
        log.Fatal(err)
    }
 
	// 创建反向代理,监听在8081端口
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        // 修改请求头,请求目的地址改成目标服务器地址
        r.Host = targetURL.Host
		proxy := reverseProxyPool.Get()
		defer reverseProxyPool.Put(proxy)
		httpProxy := proxy.(*httputil.ReverseProxy)
        // 将请求转发到目标服务器
        httpProxy.ServeHTTP(w, r)
    })
    log.Println("反向代理服务监听端口8081")
    log.Fatal(http.ListenAndServe(":8081", nil))
}

源码分析

func NewSingleHostReverseProxy(target *url.URL) *ReverseProxy {
	director := func(req *http.Request) {
        // 重写请求URL
		rewriteRequestURL(req, target)
	}
	return &ReverseProxy{Director: director}
}

func rewriteRequestURL(req *http.Request, target *url.URL) {
	targetQuery := target.RawQuery
	req.URL.Scheme = target.Scheme
    // 重写req的Host,从而把请求转发到后端
	req.URL.Host = target.Host
	req.URL.Path, req.URL.RawPath = joinURLPath(target, req.URL)
	if targetQuery == "" || req.URL.RawQuery == "" {
		req.URL.RawQuery = targetQuery + req.URL.RawQuery
	} else {
		req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
	}
}

1. 使用ReverseProxy参数Director修改请求。

2. 设置Header中X-Forward-For值为代理ip。

3. 通过连接池向后端发起请求。

4. 使用ReverseProxy参数ModifyResponse修改响应。

5. 复制后端响应头部、状态码、响应体到代理。

 

 

posted on 2025-03-29 16:00  王景迁  阅读(75)  评论(0)    收藏  举报

导航