2017-02-26 196 views
1

我正在用Golang编写一个简单的反向代理。代码如下所示:Golang反向代理到应用程序后面的nginx

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配置引起的吗?

回答

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) 

这是用于构建反向代理在&httputil.ReverseProxy{Director: director}

的功能,但你director从未修改http.Request该原始req点。它重新分配指针req = r。不相干的http.Request被修改。

+0

嗨@cshu,感谢您的及时回复。我已删除重新分配的代码,但404错误仍然存​​在。在Nginx日志中,有一条访问记录,所以代理请求可以到达目标,但是,nginx日志显示404。 –

0

该问题与请求正文。如果你看看Gin如何实现获取参数,你会发现它打开,阅读并关闭它。所以当你转发请求时,请求主体是空的。

0

我刚碰到同样的问题。我通过设置主机来解决它。 nginx使用主机(服务器名称)决定要在端口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 

作为一个侧面说明,您可以杜松子酒处理器之外创建代理和调用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) 
    } 
}