[英]Golang reverse proxy to app behind nginx
I am writing a simple reverse proxy with Golang. 我正在用Golang写一个简单的反向代理。 The code is listed below: 下面列出了代码:
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)
}
}
When I am trying to proxy one request to a REST api behind Nginx, Nginx always returns 404. However, if i directly access the REST api, it returns the result correctly. 当我尝试将一个请求代理到Nginx后面的REST api时,Nginx总是返回404。但是,如果我直接访问REST api,它将正确返回结果。 Here's my Nginx config: 这是我的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;
}
}
May I know how to debug this problem? 我可以知道如何调试此问题吗? Is it caused by Nginx configuration? 是Nginx配置引起的吗?
From https://golang.org/pkg/net/http/httputil/#ReverseProxy : 从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)
That is the function used to construct ReverseProxy in &httputil.ReverseProxy{Director: director}
这是用于在&httputil.ReverseProxy{Director: director}
构造ReverseProxy的函数
But your director
never modifies the http.Request
that original req
points to. 但是,你的director
从未修改 http.Request
该原始req
点。 It reassigns the pointer with req = r
. 它使用req = r
重新分配指针。 An irrelevant http.Request
is modified instead. 不相关的http.Request
被修改。
The issue is with request body. 问题在于请求主体。 If you look into how Gin
implement get parameter, you will find that it open, read it and close it. 如果您研究Gin
如何实现get参数,您会发现它已经打开,读取并关闭了。 So when you forward the request, the request body is empty. 因此,当您转发请求时,请求主体为空。
I just ran into this same issue. 我只是遇到了同样的问题。 I solved it by setting the Host. 我通过设置主机来解决它。 nginx uses the host(server_name) to decide which server on port 80 to serve. nginx使用host(server_name)来决定服务端口80上的哪个服务器。
req.Host = target.Host
// or
req.Host = ""
It can be set to an empty string because the url host was just set req.URL.Host = target.Host
https://golang.org/pkg/net/http/#Request 可以将其设置为空字符串,因为仅将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
As a side note, you can create the proxy outside of the gin handler and call proxy.ServeHTTP(c.Writer, c.Request)
in the gin handler. 附带一提,您可以在gin处理程序之外创建代理,然后在gin处理程序中调用proxy.ServeHTTP(c.Writer, c.Request)
。 The final result would look like this: 最终结果将如下所示:
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)
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.