You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go如何向非CONNECT类型Envoy代理发送WebSocket请求

Go WebSocket客户端对接非CONNECT型Envoy代理的推荐方案

核心思路

通过自定义http.Transport拦截WebSocket请求,将请求的实际发送目标替换为Envoy代理地址,但保留原始请求的路径、查询参数及WebSocket相关头信息。这样客户端代码可以完全按照直接访问原始目标的方式编写,无需额外修改请求结构或添加自定义头。

基于gorilla/websocket的实现示例

gorilla/websocket是Go生态中最常用的WebSocket库,支持通过Dialer关联自定义的http.Client,我们可以利用这一点实现请求转发:

package main

import (
    "net/http"
    "net/url"
    "log"
    "time"

    "github.com/gorilla/websocket"
)

func main() {
    // 配置Envoy代理地址
    proxyAddr := "ws://127.0.0.1:8080"
    proxyURL, err := url.Parse(proxyAddr)
    if err != nil {
        log.Fatalf("解析代理地址失败: %v", err)
    }

    // 创建自定义Transport,拦截并修改请求目标
    customTransport := &http.Transport{}
    originalRoundTrip := customTransport.RoundTrip
    customTransport.RoundTrip = func(req *http.Request) (*http.Response, error) {
        // 将请求的Scheme和Host替换为代理地址
        req.URL.Scheme = proxyURL.Scheme
        req.URL.Host = proxyURL.Host
        // 传递原始目标的Host信息给Envoy,用于路由匹配
        req.Header.Set("X-Forwarded-Host", req.Host)
        return originalRoundTrip(req)
    }

    // 关联自定义Transport到http.Client
    client := &http.Client{Transport: customTransport}

    // 配置WebSocket Dialer,使用自定义Client的网络连接逻辑
    dialer := websocket.Dialer{
        NetDialContext: client.Transport.(*http.Transport).DialContext,
        HandshakeTimeout: 10 * time.Second,
    }

    // 客户端代码完全按照直接访问原始目标编写
    targetWSURL := "ws://your-original-target.com/ws/chat?room=123"
    conn, resp, err := dialer.Dial(targetWSURL, nil)
    if err != nil {
        log.Fatalf("WebSocket连接失败: %v, 响应: %v", err, resp)
    }
    defer conn.Close()

    // 后续WebSocket收发逻辑与直接连接目标完全一致
    // 示例:发送消息
    err = conn.WriteMessage(websocket.TextMessage, []byte("hello from client"))
    if err != nil {
        log.Fatalf("发送消息失败: %v", err)
    }
}

其他WebSocket库的适配方式

只要目标库支持自定义http.Client或http.Transport,都可以套用类似逻辑:

  • 若库允许直接传入http.Client,直接替换其Transport即可
  • 若库依赖全局http.DefaultClient,可以修改http.DefaultClient.Transport实现全局代理(注意可能影响其他HTTP请求)

Envoy端配置配合

确保Envoy监听HTTP端口,并配置路由规则匹配X-Forwarded-Host头或原始请求路径:

# Envoy路由示例
routes:
- match:
    headers:
      x-forwarded-host:
        exact: "your-original-target.com"
  route:
    cluster: your-target-cluster

Envoy默认支持WebSocket的HTTP升级,无需额外配置监听器类型。

方案优势

相比直接向代理地址发请求并添加自定义头的方式,该方案:

  • 客户端代码更简洁直观,与直接访问目标的代码无差异
  • 无需硬编码代理地址,可通过配置集中管理
  • 保留原始请求的所有上下文信息,便于Envoy进行路由和日志记录

内容的提问来源于stack exchange,提问作者CppNoob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 18:30:59