2017-02-26 149 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) 
    } 
}