带有 lb 的 Aws ec2 不会在 websocket 上返回 101

Posted

技术标签:

【中文标题】带有 lb 的 Aws ec2 不会在 websocket 上返回 101【英文标题】:Aws ec2 with lb does not return 101 on websocket 【发布时间】:2022-01-24 06:56:03 【问题描述】:

我的应用程序有问题。 基本上,虽然一切都在本地主机上运行顺利,但当我部署到 aws websocket 连接不起作用。 问题是,当我在 ec2 上发出 wss 请求时,它似乎确实让响应离开了机器,所以我的应用程序没有变成 101 并稳定连接,而是挂起等待 1 分钟过去并获得超时,然后它返回 200 但没有建立连接。 Api 是用 go lang 和 gin 框架编写的,app 是用 js 和 React 框架编写的。 在询问一些人的建议时,他们告诉我,我可以用 https“包装”一个 wss 请求,然后通过 lb 传递它并用 nginx 升级它,但我真的找不到类似的东西。 这是我的后端代码

main.go

    

        ws.GET("/:id", func(c *gin.Context) 
            websocket.ServeWs(c, pool)
        )
    

websocket.go

ar upgrader = websocket.Upgrader
    ReadBufferSize:  1024,
    WriteBufferSize: 1024,
    CheckOrigin: func(r *http.Request) bool  return true ,


func Upgrade(w http.ResponseWriter, r *http.Request) (*websocket.Conn, error) 
    ws, err := upgrader.Upgrade(w, r, nil)
    if err != nil 
        log.Println(err)
        return ws, err
    
    return ws, nil


func ServeWs(c *gin.Context, pool *Pool) 

    w := c.Writer
    r := c.Request
    conn, err := Upgrade(w, r)
    if err != nil 
        fmt.Fprintf(w, "%+V\n", err)
    
    client := &Client
        Conn: conn,
        Pool: pool,
        ID: c.Param("id"),
    

    pool.Register <- client
    client.Read()

这是反应代码

const socket = new WebSocket(
  `$
    process.env.REACT_APP_ENV === "dev"
      ? "ws://localhost:8080"
      : "wss://api.blabla.prod"
  /ws/$sessionStorage.getItem("userID")`
);


let WebSocketConnect = () => 
  console.log("Attempting Connection...");

  socket.onopen = () => 
    console.log("Successfully Connected");
  ;

  socket.onclose = (event) => 
    console.log("Socket Closed Connection: ", event);
    // WebSocketConnect();
  ;

  socket.onerror = (error) => 
    console.log("Socket Error: ", error);
  ;
;

let sendMsg = (msg) => 
  //   console.log("sending msg: ", msg);
  socket.send(msg);
;

export  WebSocketConnect, sendMsg, socket ;

这里是 nginx 配置

server 

    listen 80;
    server_name api.blabla.prod;

    if ($http_x_forwarded_proto = 'http') 
        return 301 https://$server_name$request_uri;
    
    location /ws 
        proxy_pass "http://127.0.0.1:8080";
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    
    location / 
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header Host $http_host;
        proxy_pass       "http://127.0.0.1:8080";
    

提前致谢!

【问题讨论】:

【参考方案1】:

问题似乎出在您的 nginx 配置中,我会为您的 /ws 端点复制此问题。好像少了$proxy_add_x_forwarded_for

server 
        listen 80;
        server_name goddit.pro; // change this
        location /  // You can leave it at / or set it for another location, i.e. /ws
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
                proxy_set_header X-NginX-Proxy true;

                proxy_pass http://localhost:8080/;
                proxy_redirect off;

                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        

问题也可能出在您的 javascript 中,这是您连接和升级的方式。

window.onload = function () 
  // Somewhere in your html document
  var conn;
  // Then you need to connect
  function connectWs(id) 
    if (window["WebSocket"]) 
      conn = new WebSocket("wss://" + document.location.host + "/id/" + id);
      conn.onopen = function (evt) 
        var item = document.createElement("li");
        item.innerHTML = "<em>Connected to " + id + "</em>";
        log.appendChild(item);
      ;
      conn.onclose = function (evt) 
        var item = document.createElement("li");
        item.innerHTML = "<em>Connection to " + id + " closed</em>";
        log.appendChild(item);
      ;
      conn.onmessage = function (evt) 
        var message = JSON.parse(evt.data);
        // console.log(message);
        printMessage(message);
      ;
     else 
      var item = document.createElement("li");
      item.innerHTML = "<b>Your browser does not support WebSockets.</b>";
      log.appendChild(item);
    
  
  connectWs(id);

从 React 控制台共享错误日志后:

关闭Code 1006 是一个特殊代码,表示连接被浏览器实现异常(本地)关闭。

如果您的浏览器客户端报告关闭代码 1006,那么您应该查看 websocket.onerror(evt) 事件以了解详细信息。

【讨论】:

没有任何变化,请求确实通过了 nginx,但没有立即返回。如果这有助于 /ws 的日志是这个 ` [GIN] 2021/12/23 - 08:56:38 | 200 | 59.658382116s | 172.31.40.164 | GET "/ws/admin" 连接池大小: 0 2021/12/23 08:56:38 发生错误: websocket: close 1006 (异常关闭): unexpected EOF` 你确定你用那个重启了你的 nginx 等吗?它缺少标头、代理重定向等。 是的 sudo systemctl restart nginx 是的,检查一下。无论如何,谢谢。 用你应该记录的内容更新了答案

以上是关于带有 lb 的 Aws ec2 不会在 websocket 上返回 101的主要内容,如果未能解决你的问题,请参考以下文章

AWS - ECS - 如何在现有 ECS(带有 1 个 EC2)实例上重新部署更新的 Docker 映像?

带有 PHP SDK 的 AWS EC2 - 等到实例具有公共 DNS 名称

text 带有docker post命令的AWS EC2简单AMI

在 AWS CloudFormation 模板中,如何使用自己的 Id 标记 EC2 实例而不会出现循环引用错误?

在某些情况下,AWS ELB 不会将请求分发到 Auto Scaling 组 EC2 实例

NVidia 驱动程序停止在带有 Ubuntu 16.04 和 Tesla K80 GPU 的 AWS EC2 实例上工作