返回

Vue+Vite WebSocket 连接失败与 502 错误排查

vue.js

Vue+Vite 项目 WebSocket 连接失败及 502 Bad Gateway 错误排查

使用 Vue 和 Vite 构建的项目部署时,可能会遇到 WebSocket connection to wss failed 错误和 502 Bad Gateway 问题。这种情形通常发生在配置了 HTTPS 并通过 Docker 容器化部署时。 以下探讨问题的根源和一些解决办法。

问题剖析

根本原因在于 HTTPS 环境下 WebSocket 连接的安全要求。开发环境使用 HTTPS 时,Vite 会默认尝试通过 wss:// 建立 WebSocket 连接。如果客户端尝试建立 wss 连接失败,就会返回502 Bad Gateway 。由于浏览器的安全限制, wss 连接通常需要与页面地址的域名保持一致,并进行适当配置才能生效。如果使用了如 localhost:8080 这类本地地址, 或使用了错误的证书, 连接就可能中断。此外,反向代理(如 Nginx)在处理 WebSocket 请求时,可能需要特殊配置。 错误信息往往指向配置问题或反向代理设置的不匹配。

解决方案一:调整 vite.config.js HTTPS 设置

vite.config.js 文件中的 HTTPS 配置不正确或不完整,可能会引发该错误。具体地讲,当Vite 启动 https server 时, 客户端通过 wss://连接。这时服务端必须是公网地址才能让客户端访问成功。 一种方式是通过 Nginx 将 wss://websitename.xyz/ 反向代理到 Vite 服务的 wss://localhost:8080/。如果前端代码访问的域名与vite配置不符, 或者 Nginx配置不正确,连接便可能失效。 简单粗暴的方式是通过注释掉 vite.config.js 文件中的 https 配置来禁用HTTPS,虽然可以临时解决问题,但是不推荐。 为了解决问题,首先应当保证Vite 使用 wss 连接时的地址可以正常访问。 其次应该使用Nginx进行反向代理。

步骤:

  1. 检查 vite.config.js 的 HTTPS 配置。确保 keycert 配置指向的证书路径正确,且证书本身有效。同时检查server.host是否是0.0.0.0,以便可以在docker外部被访问到。
  2. 修改 Nginx 配置。确保 Nginx 反向代理正确配置了 WebSocket 连接所需的 upgradeconnection 请求头,正确地转发请求到localhost:8080,如下列nginx配置实例:
server {
  listen 443 ssl http2;
  server_name websitename.xyz;

  ssl_certificate /etc/letsencrypt/live/websitename.xyz/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/websitename.xyz/privkey.pem;

  location / {
    proxy_pass http://localhost:8080;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
  }
}

  1. 使用以下代码检查当前机器8080 端口是否开放:

    sudo lsof -i :8080
    

    如果显示正常端口已占用, 说明vue 项目正常运行。

  2. 如果使用docker compose up, 需要确保nginx配置是在 docker-compose.yml中进行,并且websitename.xyz 是指向了 docker 服务机器的公网 IP 的。

  3. 完成以上配置后,务必重启 docker 以及 nginx 服务

代码示例 (vite.config.js):

import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import fs from 'node:fs'


export default defineConfig({
  plugins: [vue()],

  server: {
    port: 8080,
    host: '0.0.0.0',
      // 取消以下注释则取消 https
    /*  https: {
       key: fs.readFileSync('./privkey.pem'),
       cert: fs.readFileSync('./fullchain.pem'),
     }  */
  }
})

额外提示:

  • Nginx需要与docker使用同一个证书。
  • 在某些云服务器环境中,防火墙可能会阻碍对特定端口的访问。需要检查服务器的防火墙规则,确保8080端口对外开放,或者是使用更常见的如80,443 等端口。

解决方案二: 使用 build 命令 规避 开发环境 Websocket 连接问题

如果你的项目并不需要 热重载(hot reload) 功能,一种简单且有效的方式是,使用 build 命令 构建生产版本代码,并在 serve 的时候指定主机名 host 和 端口 portbuild命令生成静态文件,省去了 Web Socket 的复杂性,并直接部署。通过 Dockerfile 在容器启动时执行 build 操作。 如果一定要使用热重载功能, 应按照 “解决方案一” 中的方法进行调整。

步骤:

  1. 修改 Dockerfile。使用 npm run build 命令构建项目,并将serve 指令修改为 npm run serve -- --host 0.0.0.0 --port 8080 ,让程序运行在特定的host和port 上, 确保生产环境没有热重载等调试需求,

  2. 构建 Docker 镜像并运行容器,检查是否依然有502 Bad GatewayWebSocket connection 的错误。

代码示例 (Dockerfile):

FROM node:18

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .

RUN ["npm", "run", "build"]
CMD ["npm", "run", "serve", "--", "--host", "0.0.0.0", "--port", "8080"]

补充说明:

  • 使用build命令时,生产版本代码会编译压缩,访问速度会明显提升。
  • 这种方式禁用了 Vite 热重载功能。修改源代码需要重新构建容器才能生效。

通过对 vite.config.js 配置,以及Dockerfile设置的优化调整,基本上能够应对部署时常见的 WebSocket 和 502 问题。解决过程中注意理解错误的本质和系统配置的运作原理, 可以有效避免重复性错误。 务必认真排查 Nginx 配置文件与证书相关的问题。