简体   繁体   English

Golang反向代理到Nginx之后的应用

[英]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.

相关问题 nginx 反向代理意外重定向 - nginx reverse proxy unexpected redirect NodeBB在Nginx反向代理上的速度非常慢 - NodeBB horribly slow over Nginx reverse proxy 无法使用 docker 中的 nginx 反向代理从外部访问 - can't access from outside with nginx reverse proxy in docker 通过使用公共反向代理(可以访问 Internet)将 NAT 后面的客户端公开到 Internet - Expose client behind NAT to internet by using a public reverse-proxy (with access to the internet) docker-compose Nextcloud Instance behind reverse proxy Bad gateway 502 - docker-compose Nextcloud Instance behind reverse proxy Bad gateway 502 如何通过公共 nginx 反向代理限制访问以允许 VPC(在 AWS 中)内的所有内容? - How can I restrict access to allow everything within a VPC (in AWS) through a public nginx reverse proxy? docker-compose:如何将 docker 容器与“外部”隔离(詹金斯容器 + nginx 反向代理) - docker-compose : How can I isolate a docker container from “outside” (jenkins container + nginx reverse proxy) 不同域不同phpmyadmin服务和“同端口”问题(nginx反向代理,docker) - Different domain with different phpmyadmin service and the "same port" problem (nginx reverse proxy, docker) 代理后面的UnknownHostException - UnknownHostException behind Proxy NGINX反向代理+ ngx_upstream_resolveMK-尝试从ECS服务发现Route53自动命名中解析SRV - NGINX Reverse Proxy + ngx_upstream_resolveMK - Trying to resolve SRV from ECS Service Discovery Route53 Auto Naming
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM