【问题标题】:Golang reverse proxy to app behind nginxGolang反向代理到nginx后面的应用程序
【发布时间】:2017-02-26 08:46:36
【问题描述】:

我正在用 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配置造成的吗?

【问题讨论】:

    标签: networking nginx go reverse-proxy


    【解决方案1】:

    来自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)
    

    也就是&amp;httputil.ReverseProxy{Director: director}中用来构造ReverseProxy的函数

    但是您的director 从不修改原始req 指向的http.Request。它用req = r 重新分配指针。改为修改不相关的http.Request

    【讨论】:

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

    问题在于请求正文。如果你查看Gin 是如何实现get 参数的,你会发现它打开、读取并关闭它。所以当你转发请求时,请求体是空的。

    【讨论】:

      【解决方案3】:

      我刚刚遇到了同样的问题。我通过设置主机解决了它。 nginx 使用 host(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)
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2016-01-12
        • 2015-03-27
        • 2021-05-04
        • 2021-05-22
        • 2019-08-09
        • 2021-02-04
        • 1970-01-01
        • 1970-01-01
        • 2014-09-06
        相关资源
        最近更新 更多