Golang反向代理到nginx后面的应用程序

时间:2017-02-26 08:46:36

标签: networking nginx go reverse-proxy

我正在用Golang编写一个简单的反向代理。代码如下:

func NewMultiHostProxy(target_urls []string) gin.HandlerFunc {
    var urls []*url.URL
    for i := 0; i < len(target_urls); i++ {
        target, err := url.Parse(target_urls[i])
        if err != nil {
            fmt.Errorf("Error parsing url")
            return nil
        }
        urls = append(urls, target)
    }
    return func(c *gin.Context) {
        director := func(req *http.Request) {
            target := urls[rand.Int()%len(urls)]
            r := c.Request
            req = r
            req.URL.Scheme = target.Scheme
            req.URL.Host = target.Host
            req.URL.Path = target.Path
            req.Header.Set("X-GoProxy", "GoProxy")
            if target.RawQuery == "" || req.URL.RawQuery == "" {
                req.URL.RawQuery = target.RawQuery + req.URL.RawQuery
            } else {
                req.URL.RawQuery = target.RawQuery + "&" + req.URL.RawQuery
            }
            log.Print(req.URL)
        }
        proxy := &httputil.ReverseProxy{Director: director}
        proxy.ServeHTTP(c.Writer, c.Request)
    }
}

当我尝试将一个请求代理到Nginx后面的REST api时,Nginx总是返回404.但是,如果我直接访问REST API,它会正确返回结果。这是我的Nginx配置:

server {
    listen       80;
    server_name  myservername;

    location /api {
        proxy_pass http://127.0.0.1:5000;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

我可以知道如何调试此问题吗?它是由Nginx配置引起的吗?

3 个答案:

答案 0 :(得分:2)

来自https://golang.org/pkg/net/http/httputil/#ReverseProxy

\"\$@\"

这是用于在 // Director must be a function which modifies // the request into a new request to be sent // using Transport. Its response is then copied // back to the original client unmodified. // Director must not access the provided Request // after returning. Director func(*http.Request)

中构建ReverseProxy的函数

但是您的&httputil.ReverseProxy{Director: director} 永远不会修改原始director指向的http.Request。它将指针重新指定为req。相反,修改了不相关的req = r

答案 1 :(得分:0)

问题在于请求正文。如果你研究Gin如何实现get参数,你会发现它打开,读取并关闭它。因此,当您转发请求时,请求正文为空。

答案 2 :(得分:0)

我刚遇到同样的问题。我通过设置主机来解决它。 nginx使用主机(server_name)来决定端口80上的服务器。

req.Host = target.Host
// or
req.Host = ""

它可以设置为空字符串,因为url主机刚刚设置为req.URL.Host = target.Host https://golang.org/pkg/net/http/#Request

    // For client requests Host optionally overrides the Host
    // header to send. If empty, the Request.Write method uses
    // the value of URL.Host. Host may contain an international
    // domain name.
    Host string

作为旁注,您可以在gin处理程序之外创建代理,并在gin处理程序中调用proxy.ServeHTTP(c.Writer, c.Request)。最终结果如下:

func NewMultiHostProxy(target_urls []string) gin.HandlerFunc {
    var urls []*url.URL
    for i := 0; i < len(target_urls); i++ {
        target, err := url.Parse(target_urls[i])
        if err != nil {
            fmt.Errorf("Error parsing url")
            return nil
        }
        urls = append(urls, target)
    }
    director := func(req *http.Request) {
        target := urls[rand.Int()%len(urls)]
        req.URL.Scheme = target.Scheme
        req.URL.Host = target.Host
        req.URL.Path = target.Path
        req.Host = ""
        req.Header.Set("X-GoProxy", "GoProxy")
        if target.RawQuery == "" || req.URL.RawQuery == "" {
            req.URL.RawQuery = target.RawQuery + req.URL.RawQuery
        } else {
            req.URL.RawQuery = target.RawQuery + "&" + req.URL.RawQuery
        }
        log.Print(req.URL)
    }
    proxy := &httputil.ReverseProxy{Director: director}
    return func(c *gin.Context) {
        proxy.ServeHTTP(c.Writer, c.Request)
    }
}