结论

如果用户访问你的网站使用的是 HTTPS,前端 Socket.IO 也应该通过 HTTPS 域名连接。连接建立后,浏览器通常会将 WebSocket 升级为 WSS。

而在服务器内部,Nginx 可以继续使用 HTTP 转发到 Node.js:

        
浏览器 ── HTTPS / WSS ──> Nginx ── HTTP ──> Node.js
        
      

因此:

  • 前端连接地址: https://example.com

  • WebSocket 实际连接: wss://example.com

  • Nginx 到 Node.js: http://127.0.0.1:3000

这两段连接使用不同协议是正常的。HTTPS 在 Nginx 处终止,Nginx 再通过 HTTP 与 Node.js 通信。


为什么前端不能直接连 HTTP?

假设你的网站是:

        
https://example.com
        
      

如果前端代码连接:

        
io("http://example.com");
        
      

浏览器可能会因为 混合内容(Mixed Content) 阻止连接:HTTPS 页面不应主动加载不安全的 HTTP 内容。

使用 WebSocket 时也一样:

  • HTTPS 页面应使用安全的 wss://

  • HTTP 页面可以使用不加密的 ws://

使用 Socket.IO 时,通常不需要手动写 wss://。直接连接当前站点即可:

        
import { io } from "socket.io-client";

const socket = io();
        
      

如果需要写完整地址:

        
const socket = io("https://example.com");
        
      

Socket.IO 会根据 HTTPS 连接使用安全的 WebSocket(WSS)。它也可能先使用 HTTP 长轮询,再尝试升级为 WebSocket。


Node.js 示例

Node.js 服务可以继续运行在普通 HTTP 上。例如:

        
import { createServer } from "node:http";
import { Server } from "socket.io";

const httpServer = createServer();

const io = new Server(httpServer, {
  cors: {
    origin: "https://example.com",
    methods: ["GET", "POST"],
  },
});

io.on("connection", (socket) => {
  console.log("客户端已连接:", socket.id);
});

httpServer.listen(3000, "127.0.0.1", () => {
  console.log("Socket.IO 服务运行在 127.0.0.1:3000");
});
        
      

这里 Node.js 不需要配置 HTTPS 证书,因为 TLS 加密由 Nginx 负责。

如果前端与 Socket.IO 服务同域,通常可以省略 cors 配置;如果跨域,则需要将 origin 设置为实际的前端来源。


Nginx 配置示例

Nginx 需要正确转发 WebSocket 的 Upgrade 和 Connection 请求头。

可以在 http 配置块中添加:

        
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}
        
      

然后在 HTTPS 的 server 配置中设置代理:

        
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate     /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    location /socket.io/ {
        proxy_pass http://127.0.0.1:3000;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_buffering off;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}
        
      

Socket.IO 默认使用 /socket.io/ 路径,前后端路径需要一致。如果你修改了 Socket.IO 的 path,Nginx 的 location 也要相应修改。

修改 Nginx 配置后,可以检查并重新加载:

        
nginx -t
nginx -s reload
        
      

常见错误

1. HTTPS 页面连接 HTTP

        
io("http://example.com");
        
      

可能被浏览器以混合内容为由拦截。应改为:

        
io("https://example.com");
        
      

或者同域时直接写:

        
io();
        
      

2. Nginx 没有转发 WebSocket 请求头

如果缺少 Upgrade 和 Connection 配置,长轮询可能正常,但 WebSocket 升级可能失败。

3. Nginx 路径与 Socket.IO 路径不一致

默认路径是 /socket.io/。如果代理路径或 Socket.IO 的 path 配置不一致,客户端可能出现 404 或连接失败。

4. 超时时间过短

WebSocket 是长连接。如果代理读取超时时间太短,连接可能被 Nginx 关闭,可以根据业务设置合适的 proxy_read_timeout。


总结

你的部署方式可以保持为:

        
浏览器访问 HTTPS
        ↓
Nginx 处理 HTTPS/WSS
        ↓
Nginx 通过 HTTP 转发到 Node.js
        
      

所以,前端连接 HTTPS 域名,Node.js 后端仍然可以使用 HTTP。不要让 HTTPS 页面直接连接 http://,并确保 Nginx 配置了 WebSocket 升级头。