在 AWS Application Load Balancer 上使用 Go 时,WebSocket 连接失败并显示 301

WebSocket connection fails with 301 while using Go on AWS Application Load Balancer

我正在尝试 运行 在 AWS Application Load Balancer 上使用 WebSockets 的 Go 服务器,但我得到了 'Error during WebSocket handshake: Unexpected response code: 301'

AWS 表示 Application Load Balancer 通过 ws:// 协议支持 WebSockets,但我找不到除以下内容以外的任何其他文档:

这里是aws load-balancer link

The Application Load Balancer supports two additional protocols: WebSocket and HTTP/2.

WebSocket allows you to set up long-standing TCP connections between your client and your server. This is a more efficient alternative to the old-school method which involved HTTP connections that were held open with a “heartbeat” for very long periods of time. WebSocket is great for mobile devices and can be used to deliver stock quotes, sports scores, and other dynamic data while minimizing power consumption. ALB provides native support for WebSocket via the ws:// and wss:// protocols.

我可以 JavaScript 通过本地 WebSockets 连接到我的 Go 服务器,但是当我部署 AWS 时它不起作用。这是 JavaScript 显示 301 错误的时候。

Application Load Balancer 正在侦听 HTTP: 80,并且该流量被定向到 HTTPS: 443。所有安全组的设置都非常相似,以允许流量通过。如果我在部署在 AWS 上时执行正常的 GET 调用以从我的服务器检索数据,它工作得很好。

连接本地主机的本地调用

<script>
    let socket = new WebSocket("ws://localhost:8080/websocket")

    console.log("Attempting Websocket Connection")

    socket.onopen = () => {
        console.log("Successfully Connected");
        socket.send("Hi From the Client!")
    }

    socket.onclose = (event) => {
        console.log("Socket Closed Connection: ", event)
    }

    socket.onmessage = (msg) => {
        console.log(msg);
    }

    socket.onerror = (error) => {
        console.log("Socket Error: ", error)
    }
</script>

连接到不工作的远程服务器。

<script>
    let socket = new WebSocket("ws://myexamplesite.com/websocket")

    console.log("Attempting Websocket Connection")

    socket.onopen = () => {
        console.log("Successfully Connected");
        socket.send("Hi From the Client!")
    }

    socket.onclose = (event) => {
        console.log("Socket Closed Connection: ", event)
    }

    socket.onmessage = (msg) => {
        console.log(msg);
    }

    socket.onerror = (error) => {
        console.log("Socket Error: ", error)
    }
</script>

nginx.conf

events {
    worker_connections 1024;
}

http {
  server_tokens off;
  server {
    listen 80;

    location / {
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header Host            $http_host;
      proxy_pass http://web:8080/;
    }
  }
}

我希望能够建立 WebSocket 连接,但从 JavaScript 文件返回以下错误:

与 'ws://myexamplesite.com/websocket' 的 WebSocket 连接失败:WebSocket 握手期间出错:意外的响应代码:301

首先检查您在 AWS ALB 配置方面的一切是否正确,以及请求是否到达 Nginx 服务器,您可以在日志中检查。也尝试通过 Nginx 访问你的 websocket URL。您需要在 Nginx 中进行额外的配置以支持您所在位置的 websockets,如此处所述:

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";

我也遇到过同样的问题,使用这个配置开始变得轻而易举。

参考:Nginx WebSocket proxying

注意:Websockets 肯定可以与 AWS ALB 一起使用,所以不要怀疑那部分。

我能够通过结合这两个答案来让它工作。

nginx.conf现在看起来像

http {
  server_tokens off;
  server {
    listen 80;

    location / {
      proxy_set_header X-Forwarded-For $remote_addr;
      proxy_set_header Host            $http_host;
      proxy_pass http://web:8080/;
    }

    location /websocket {
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "upgrade";
           proxy_pass http://web:8080/websocket;
    }
  }
}

然后将JavaScript文件ws://改成wss://

<script>
    let socket = new WebSocket("wss://myexamplesite.com/websocket")

    console.log("Attempting Websocket Connection")

    socket.onopen = () => {
        console.log("Successfully Connected");
        socket.send("Hi From the Client!")
    }

    socket.onclose = (event) => {
        console.log("Socket Closed Connection: ", event)
    }

    socket.onmessage = (msg) => {
        console.log(msg);
    }

    socket.onerror = (error) => {
        console.log("Socket Error: ", error)
    }
</script>