如何将wss反向代理实现为gin路由?

huangapple go评论88阅读模式
英文:

How do I implement a wss reverse proxy as a gin route?

问题

我最近刚开始用Go编程,所以还不太熟练。

我有一个使用情况,我想将反向代理作为gin路由来实现。所以我的路由看起来像这样:

server.router.POST("/console", server.proxyConsoleUrl)

我的处理函数大致如下:

func (server *Server) proxyConsoleUrl(ctx *gin.Context) {
    director := func(req *http.Request) {
        r := ctx.Request
        // 这个不起作用,wss协议不被支持
        req.URL.Scheme = "wss"
        req.URL.Host = "192.168.******:8006"
        // 被代理的路径应该被覆盖
        req.URL.RawPath = "/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something"
        req.Header["my-header"] = []string{r.Header.Get("my-header")}
        // Golang将首字母大写的header转为驼峰命名
        delete(req.Header, "My-Header")
        // 这个header必须添加到每个被代理的请求中
        req.Header["Authorization"] = []string{"MYCUSTOMHEADER"}
    }
    proxy := &httputil.ReverseProxy{Director: director, Transport: &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        Dial: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).Dial,
        TLSHandshakeTimeout: 10 * time.Second,
        TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
    }}
    proxy.ServeHTTP(ctx.Writer, ctx.Request)
}

所以我的第一个问题是,据我所知,httputil.ReverseProxy不支持WebSocket,并且在运行代码时我注意到了这一点:

httputil: unsupported protocol scheme "wss"

第二个问题是,我想覆盖后端URL,并添加代理添加的自定义头部。

也许有人有办法实现这个,如果可能的话。-提前感谢。

英文:

I just recently started coding in go and thus I am not so skilled yet.

I have a use case where I want to implement a reverse proxy as a gin route.
So my route looks like this:

server.router.POST("/console", server.proxyConsoleUrl)

And my handler function something like this:

func (server *Server) proxyConsoleUrl(ctx *gin.Context) {
	director := func(req *http.Request) {
		r := ctx.Request
		// This is not working, scheme wss is not supported
		req.URL.Scheme = "wss"
		req.URL.Host = "192.168.******:8006"
		// The path which gets proxied should be overriden
		req.URL.RawPath = "/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something"
		req.Header["my-header"] = []string{r.Header.Get("my-header")}
		// Golang camelcases headers
		delete(req.Header, "My-Header")
		// This header has to be added to every request which gets proxied
		req.Header["Authorization"] = []string{"MYCUSTOMHEADER"}
	}
	proxy := &httputil.ReverseProxy{Director: director, Transport: &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
	}}
	proxy.ServeHTTP(ctx.Writer, ctx.Request)
}

So my first problem is, that httputil.ReverseProxy doesn't support web socket as far as I know and noticed when running my code:

httputil: unsupported protocol scheme "wss"

The Second problem is, that I want to override the backend url as well as add custom headers which are added by the proxy.

Maybe someone has an idea hot to implement this, if it's even possible. -Thanks in advance

答案1

得分: 1

WebSocket支持已添加到Go版本1.12中的httputil.ReverseProxy。

使用url.Parse("https://192.168.******:8006/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something")的结果来设置目标URL。这解决了以下问题:

  • WebSocket协议在传输中使用的是"http"或"https",而不是"wss"。
  • 当RawPath不是Path的有效转义时,将忽略RawPath。有关详细信息,请参阅EscapedPath。因为问题中的RawPath包含查询字符串,所以它永远不会是Path的有效转义。客户端的路径始终按原样使用。客户端的查询字符串也是如此。

创建一次代理并重用它。重要的是根据Transport文档创建并重用单个传输。重用代理可以实现这个目标。

func createProxy() *httputil.ReverseProxy {
    target, _ := url.Parse("https://192.168.******:8006/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something")
    director := func(req *http.Request) {
        req.URL = target
        req.Header["my-header"] = []string{req.Header.Get("my-header")}
        delete(req.Header, "My-Header")
        req.Header["Authorization"] = []string{"MYCUSTOMHEADER"}
    }
    return &httputil.ReverseProxy{Director: director, Transport: &http.Transport{
        Proxy: http.ProxyFromEnvironment,
        Dial: (&net.Dialer{
            Timeout:   30 * time.Second,
            KeepAlive: 30 * time.Second,
        }).Dial,
        TLSHandshakeTimeout: 10 * time.Second,
        TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
    }}
}

var proxy = createProxy()

func (server *Server) proxyConsoleUrl(ctx *gin.Context) {
    proxy.ServeHTTP(ctx.Writer, ctx.Request)
}
英文:

WebSocket support was added to httputil.ReverseProxy in Go version 1.12.

Use the result of url.Parse("https://192.168.******:8006/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something") to set the target URL. This fixes the following issues:

  • The WebSocket protocol uses "http" or "https" on the wire, not "wss".
  • RawPath is ignored when RawPath is a not a valid escaping of Path. See EscapedPath for the details. Because the RawPath in the question includes a query string, it will never be a valid escaping of Path. The client's path is alway used as is. Ditto for the client's query string.

Create the proxy once and reuse it. The important point is to create an reuse a single transport per the Transport documentation. Reusing the proxy accomplishes that goal.

func createProxy() *httputil.ReverseProxy {
	target, _ := url.Parse("https://192.168.******:8006/api2/json/nodes/something/qemu/123/vncwebsocket?port=5900&vncticket=something")
	director := func(req *http.Request) {
		req.URL = target
		req.Header["my-header"] = []string{req.Header.Get("my-header")}
		delete(req.Header, "My-Header")
		req.Header["Authorization"] = []string{"MYCUSTOMHEADER"}
	}
	return &httputil.ReverseProxy{Director: director, Transport: &http.Transport{
		Proxy: http.ProxyFromEnvironment,
		Dial: (&net.Dialer{
			Timeout:   30 * time.Second,
			KeepAlive: 30 * time.Second,
		}).Dial,
		TLSHandshakeTimeout: 10 * time.Second,
		TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
	}}
}

var proxy = createProxy()

func (server *Server) proxyConsoleUrl(ctx *gin.Context) {
	proxy.ServeHTTP(ctx.Writer, ctx.Request)
}

huangapple
  • 本文由 发表于 2022年8月1日 08:28:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/73187877.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定