Go 使用httputil.ReverseProxy时,mux.Vars为空

Go 使用httputil.ReverseProxy时,mux.Vars为空,go,gorilla,Go,Gorilla,我试图同时使用gorilla mux和httputil.ReverseProxy,但当试图获取mux.Vars时,它是空的。据我们所知,http.Request指针似乎是原始请求的一个浅拷贝,它应该仍然可以工作 有什么想法吗 这里有两个不同的问题 第一,您没有使用mux.Router,因此gorilla/mux没有机会预处理您的请求。换句话说,请求直接从http包发送到您的反向代理。此问题有一个简单的解决方法: r := mux.NewRouter() for _, route := rang

我试图同时使用gorilla mux和httputil.ReverseProxy,但当试图获取mux.Vars时,它是空的。据我们所知,http.Request指针似乎是原始请求的一个浅拷贝,它应该仍然可以工作

有什么想法吗


这里有两个不同的问题

第一,您没有使用
mux.Router
,因此
gorilla/mux
没有机会预处理您的请求。换句话说,请求直接从
http
包发送到您的反向代理。此问题有一个简单的解决方法:

r := mux.NewRouter()
for _, route := range routes {
    r.Handle(route.match, NewProxy(&route))
}
http.Handle("/", r)
第二个问题比第一个问题更棘手。这个问题与如何实现
mux
包有关。如果您查看
mux.Vars()
实现,您将看到它使用了一种称为
Context
的东西。如中所述,
上下文是存储请求生存期内共享的值的内容。简化的上下文实现将是:

type Context map[*http.Request]interface{}

func (c Context) Set(req *http.Request, v interface{}) {
    c[req] = v
}

func (c Context) Get(req *http.Request) interface{} {
    return c[req]
}
如您所见,给定一个
http.Request
,我们可以在上下文中存储值。稍后,我们可以使用相同的
上下文
和相同的
http.Request
检索这些值
mux
使用全局
上下文
存储路由过程中解析的VAR,以便您可以使用标准
http.request
。但是,由于
httputil.ReverseProxy
传递实际请求的副本,并且
Context
按请求链接值,因此这个新的
请求
上下文
中没有值

要修复它,您可以基于
httputil.ReverseProxy
实现自己的
ReverseProxy

type MyReverseProxy struct {
    httputil.ReverseProxy
    Director func(inr, outr *http.Request)
}

func (p *MyReverseProxy) ServeHTTP(rw http.ResponseWriter, inr *http.Request) {
    p.ReverseProxy.Director = func(outr *http.Request) {
        p.Director(inr, outr)
    }
    p.ReverseProxy.ServeHTTP(rw, inr)
}

func NewProxy(r *route) http.Handler {
    director := func(inr, outr *http.Request) {
        out, _ := url.Parse(r.base)

        outr.URL.Scheme = out.Scheme
        outr.URL.Host = out.Host
        outr.URL.Path = out.Path + "/" + mux.Vars(inr)["path"] 

        log.Printf("IN VARS: %#v\n", mux.Vars(inr)) // Now inr has proper vars
        log.Printf("OUT VARS: %#v\n", mux.Vars(outr))
    }
    return &MyReverseProxy{Director: director}
您甚至可以使用
context
并保留
Director
声明:

type MyReverseProxy struct {
    httputil.ReverseProxy
    Director func(req *http.Request)
}

func (p *MyReverseProxy) ServeHTTP(rw http.ResponseWriter, inr *http.Request) {
    p.ReverseProxy.Director = func(outr *http.Request) {
        context.Set(outr, "in_req", inr)
        p.Director(outr)
    }
    p.ReverseProxy.ServeHTTP(rw, inr)
}

func NewProxy(r *route) http.Handler {
    director := func(outr *http.Request) {
        out, _ := url.Parse(r.base)

        inr := context.Get(outr, "in_req").(*http.Request)
        outr.URL.Scheme = out.Scheme
        outr.URL.Host = out.Host
        outr.URL.Path = out.Path + "/" + mux.Vars(inr)["path"]

        log.Printf("IN VARS: %#v\n", mux.Vars(inr)) // Now inr has proper vars
        log.Printf("OUT VARS: %#v\n", mux.Vars(outr))
    }
    return &MyReverseProxy{Director: director}
}
这两种实现对我来说都很棘手。他们必须在每次调用中更改
httputil.ReverseProxy
Director
。因此,我可能接受
mux
在这里不是一个好的选择,相反,我将使用一些更简单的解决方案:

var routes = []route{
    route{match: "/api/", base: "https://api.bar.com/5"},
    route{match: "/sales/", base: "https://sales.bar.com/3"},
}

func NewProxy(r *route) http.Handler {
    director := func(req *http.Request) {
        out, _ := url.Parse(r.base)

        req.URL.Scheme = out.Scheme
        req.URL.Host = out.Host
        req.URL.Path = out.Path + "/" + strings.TrimPrefix(req.URL.Path, r.match)
    }
    return &httputil.ReverseProxy{Director: director}
}

您可以阅读以实现基于正则表达式的复杂解决方案。

Oops(不使用mux路由器)是解决问题的最后一刻尝试,但在提出问题之前,我似乎没有足够早地撤销。我不知道上下文起了作用。不使用mux路由器并修剪前缀,就像上一个示例中那样,是我想要的方式,但由于需要将URL与正则表达式匹配,所以没有这样做。也许,正如你所建议的,走那条路会让事情变得更干净。谢谢你的帮助
var routes = []route{
    route{match: "/api/", base: "https://api.bar.com/5"},
    route{match: "/sales/", base: "https://sales.bar.com/3"},
}

func NewProxy(r *route) http.Handler {
    director := func(req *http.Request) {
        out, _ := url.Parse(r.base)

        req.URL.Scheme = out.Scheme
        req.URL.Host = out.Host
        req.URL.Path = out.Path + "/" + strings.TrimPrefix(req.URL.Path, r.match)
    }
    return &httputil.ReverseProxy{Director: director}
}