每个主机的 Golang ReverseProxy

我正在尝试在 Go 中实现一个反向代理,它根据嵌入在 URL 中的某些租户将流量代理到不同的主机。实现看起来像这样:


type Offloader struct {

    tenantHostMap   map[string]string                   // Map a tenant to its host:port

    tenantProxyMap  map[string](*httputil.ReverseProxy) // Map a tenant to its reverse proxy

}


func (o *Offloader) OnCreate() {


    // Tenants Map

    o.tenantHostMap = make(map[string]string)

    o.tenantProxyMap = make(map[string]*httputil.ReverseProxy)

    o.PopulateTenantHostMap()


    // Rx

    http.HandleFunc("/", o.ServeHTTP)

    go http.ListenAndServe(":5555", nil)


}


// ServeHTTP is the callback that is called each time a Http Request is received.

func (o *Offloader) ServeHTTP(w http.ResponseWriter, req *http.Request) {

    incomingUrl := req.URL.RequestURI()

    tenant := o.GetTenantFromUrl(incomingUrl)


    if proxy, ok := o.tenantProxyMap[tenant]; ok {

        proxy.ServeHTTP(w, req)

    }


    if remoteHostAddr, ok := o.tenantHostMap[tenant]; ok {

        remoteUrl, err := url.Parse(fmt.Sprintf("http://%s", remoteHostAddr))

        if err != nil {

            return

        }

        proxy := httputil.NewSingleHostReverseProxy(remoteUrl)

        o.tenantProxyMap[tenant] = proxy

        proxy.ServeHTTP(w, req) // non blocking


    } else {

        panic("Unknown Tenant")

    }

}

当收到新的 HTTP 请求时,我从 URL 中获取租户。如果这是我第一次看到这个租户,我会创建一个新的 ReverseProxy,否则我会尝试使用我之前创建并存储在tenantProxyMap.


当我对此进行测试时,出现以下错误:


2022/04/05 12:31:01 http: proxy error: readfrom tcp ****: http: invalid Read on closed Body

2022/04/05 12:31:01 http: superfluous response.WriteHeader call from net/http/httputil.(*ReverseProxy).defaultErrorHandler (reverseproxy.go:190)

如果我为每个请求创建一个新的反向代理而不是重复使用相同的代理,则不会发生错误。


我认为代理是按主机而不是按请求(顾名思义),所以我想知道为什么会发生此错误?


我知道我需要保护地图免受并发读/写的影响,但目前这无关紧要。


冉冉说
浏览 144回答 1
1回答

尚方宝剑之说

问题是,在以前的代理已经存在的情况下,您首先将请求传递给它 - 然后仍然重新创建代理,并再次传递请求。换句话说:当 tentantProxyMap 已经为该租户填充时,您正在为每个传入请求发出两个代理请求。该ReverseProxy实现会关闭req.Body,因此您第二次将请求传递给代理时,它会尝试从已经关闭的主体中读取。结果您看到了http: invalid Read on closed Body错误。您应该尝试在代理请求后返回,例如通过添加return:if proxy, ok := o.tenantProxyMap[tenant]; ok {    proxy.ServeHTTP(w, req)    return}
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go