HTTPS前端无法连接ws协议Socket.io服务,如何切换为wss?
前端部署在Vercel、后端部署在Railway,二者均启用HTTPS加密。后端搭建Socket.io服务器后出现如下错误:
The page at 'https://codingflux.vercel.app/editor/Test/6560b5a38544a66357dd' was loaded over HTTPS, but attempted to connect to the insecure WebSocket endpoint 'ws://codingflux-backend-production.up.railway.app/socket.io/?EIO=4&transport=websocket'.
已知后端域名支持HTTPS(https://codingflux-backend-production.up.railway.app/),但前端连接时使用了不安全的ws协议,希望将Socket URL转为wss协议。
后端代码如下:
const express = require("express"); const app = express(); const http = require("http"); const cors = require('cors'); const { Server } = require("socket.io"); const Actions = require('./Actions'); app.use(cors()); const server = http.createServer(app); const io = new Server(server, { cors: { origin: 'https://codingflux.vercel.app/', methods: ['GET', 'POST'], }, }); const users = {}; //Get an array of all the users connected in the room as an array of objects with socketId and username as their attributes. const getAllConnectedClients = (roomId) => { return Array.from(io.sockets.adapter.rooms.get(roomId)).map((socketId) => { return { socketId, username: users[socketId] } }) } io.on('connection', (socket) => { //Listen for any join event populate the users object and get all connected clients and for every client emit another event joined. socket.on(Actions.JOIN, ({roomId, username}) => { const userName = username; users[socket.id] = username; socket.join(roomId); //This clients array is send as one of the values to the client side ehere it is used to set the state of client. const clients = getAllConnectedClients(roomId); clients.forEach(({socketId}) => { io.to(socketId).emit(Actions.JOINED, { clients, userName, socketId: socket.id }) }) }) //Executes whenever a user leaves the room. socket.on('disconnecting', () => { const rooms = [...socket.rooms]; rooms.forEach((roomId) => { socket.in(roomId).emit(Actions.DISCONNECTED,{ socketId : socket.id, username : users[socket.id] }) }); delete users[socket.id]; socket.leave(); }) //Listen to any code change events from the client side whenever user writes something in code editor and broadcast it to all other connected clients. socket.on(Actions.CODE_CHANGE, ({ roomId, code, name }) => { socket.in(roomId).emit(Actions.CODE_CHANGE, { code : code, name }); }) //This event is emited from the as a response of joined event from the client side. //Emitted by everyone except the newly joined user. socket.on(Actions.SYNC_CODE, ({ code, socketId, name }) => { //Emit an event as a response to change code in new users editor. This event is emited once when a new user first joines or the page reloads. socket.to(socketId).emit(Actions.CODE_CHANGE, { code : code, name : name }); }) }) const PORT = 5000; server.listen(PORT, () => {console.log(`Alpha is online on ${PORT}`)});
要解决ws转wss的问题,核心是适配HTTPS环境的连接规则,具体步骤如下:
1. 前端使用HTTPS地址初始化Socket连接
前端初始化Socket.io客户端时,直接传入后端的HTTPS域名,Socket.io会自动将协议转为wss,无需手动指定ws://前缀。示例代码:
// 前端代码示例 import { io } from "socket.io-client"; const socket = io("https://codingflux-backend-production.up.railway.app", { transports: ["websocket"] // 可选,强制使用WebSocket传输 });
如果之前前端硬编码了ws://开头的地址,直接替换为HTTPS域名即可。
2. 后端配置适配Railway反向代理
Railway会自动为应用提供HTTPS反向代理,后端无需手动配置HTTPS证书,但需要让Socket.io识别反向代理的真实协议。在Socket.io的配置中添加trustProxy: true,让它从请求头中获取正确的协议信息:
const io = new Server(server, { cors: { origin: 'https://codingflux.vercel.app/', methods: ['GET', 'POST'], }, trustProxy: true // 新增配置,适配Railway反向代理环境 });
该配置会让Socket.io根据X-Forwarded-Proto请求头自动判断使用ws还是wss协议,确保后端返回的连接地址符合HTTPS环境要求。
3. 优化端口配置
Railway会自动映射端口,后端代码应监听环境变量中的端口,避免硬编码导致的环境不兼容:
const PORT = process.env.PORT || 5000; server.listen(PORT, () => {console.log(`Alpha is online on ${PORT}`)});
完成以上步骤后,前端即可通过wss协议安全连接到后端Socket.io服务器,解决混合内容错误。
内容的提问来源于stack exchange,提问作者Nishant Sharma

