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

Nginx反向代理Golang Gorilla Websocket服务时连接后立即断开如何解决

问题原因
  • Origin校验拦截:Gorilla Websocket默认开启Origin跨域校验,若客户端请求的Origin域名和后端服务允许的域名不匹配,服务端会在握手成功后直接主动断开连接,这是该场景下最常见的触发原因。
  • Nginx代理超时配置缺失:当前配置没有显式设置代理读写超时,Nginx默认的proxy_read_timeout为60秒,若连接建立后60秒内没有任何数据传输就会自动断开;如果是刚建立就断开的情况,大概率是上面的Origin校验问题,但超时也会导致短时间无数据就断的问题。
  • Upgrade/Connection头适配不全:当前配置的Connection头写死为"upgrade",仅适配WebSocket请求,若有混合普通HTTP请求的场景会导致异常,同时部分场景下未传递Sec-WebSocket-Key、Sec-WebSocket-Version等Websocket专属头也会导致握手异常断开。
  • 后端服务端口暴露问题:确认internalexample.com:8000的服务没有开启IP白名单、端口限制,未拦截Nginx节点的访问请求。
修复方案

1. 调整Gorilla Websocket的Origin校验逻辑

如果你的服务允许跨域访问,或者确认Origin来源合法,可以在初始化Upgrader的时候关闭Origin校验,或者自定义校验逻辑:

var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    // 关闭Origin校验,生产环境建议自定义CheckOrigin函数做合法校验
    CheckOrigin: func(r *http.Request) bool {
        return true
        // 生产环境可以用下面的逻辑校验指定域名
        // origin := r.Header.Get("Origin")
        // return origin == "http://example.com"
    },
}

2. 调整Nginx反向代理配置

补充超时配置、优化Websocket头处理逻辑,修改后的配置如下:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_set_header X-Real-IP  $remote_addr;
        # 修正X-Forwarded-For为追加模式,保留整条链路的代理IP信息
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        # 传递Websocket专属头
        proxy_set_header Sec-WebSocket-Key $http_sec_websocket_key;
        proxy_set_header Sec-WebSocket-Version $http_sec_websocket_version;
        
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        # 动态设置Connection头,只有Upgrade请求才设为upgrade,兼容普通HTTP请求
        proxy_set_header Connection $connection_upgrade;
        
        # 调整代理超时,根据业务需要设置,单位秒,这里设为1小时无数据传输才断开
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        # 禁用代理缓存,Websocket是流式传输不需要缓存
        proxy_buffering off;
        
        proxy_pass http://internalexample.com:8000;
    }
    # 全局定义Connection头的映射规则
    map $http_upgrade $connection_upgrade {
        default upgrade;
        ''      close;
    }
}

3. 辅助排查手段

如果修改后还是有问题,可以在服务端捕获Websocket断开的错误码确认原因:

// 读取消息时捕获错误
_, msg, err := conn.ReadMessage()
if err != nil {
    // 打印错误信息,gorilla的错误会明确提示Origin not allowed之类的具体原因
    log.Printf("websocket断开,错误:%v", err)
    return
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:15:05