我有一个 React 前端和 NodeJS 后端,使用 nginx 提供服务和负载平衡。当我在本地运行 nginx 和 npm run dev 时,我的设置有效,但当我使用 docker compose 通过 docker 容器运行它时,Web 套接字无法连接。 在控制台中:
websocket.js:43 WebSocket connection to 'ws://localhost/socket.io/?userId=6500d7f273ec607346da303c&EIO=4&transport=websocket' failed:
我很茫然,我已经尝试了所有能找到的方法。这是我的设置。
docker-compose.yml
services:
ws1:
image: bark-mate-be
environment:
- APPID=1111
- APPPORT=8081
networks:
- loadbalancing
ports:
- "8081:8080"
ws2:
image: bark-mate-be
environment:
- APPID=2222
- APPPORT=8082
ports:
- "8082:8080"
networks:
- loadbalancing
ws3:
image: bark-mate-be
environment:
- APPID=3333
- APPPORT=8083
ports:
- "8083:8080"
networks:
- loadbalancing
barkmatefrontend:
image: bark-mate-fe
ports:
- "3000:80"
networks:
- loadbalancing
depends_on:
- db
- ws1
- ws2
- ws3
db:
volumes:
- barkMate_db:/data/db
image: mongo:latest
ports:
- "27017:27017"
volumes:
barkMate_db:
networks:
loadbalancing:
nginx.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream loadbalancer {
# ip_hash;
hash $remote_addr consistent;
server ws1:8081;
server ws2:8082;
}
server {
listen 80;
listen [::]:80;
server_name localhost;
location /socket.io/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://loadbalancer;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /api/ {
proxy_pass http://loadbalancer;
proxy_buffering on;
}
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
}
socketio.js
import { io } from "socket.io-client";
const user = JSON.parse(localStorage.getItem("user"));
export let socket = io("http://localhost:80", {
path: "/socket.io/",
auth: { token: "token" },
query: { userId: user ? JSON.parse(localStorage.getItem("user"))._id : "" },
autoConnect: false,
transports: ["websocket"],
withCredentials: true,
});
socket.onAnyOutgoing((e, m) => {
console.log("any out going", e, m);
});
socket.on("connect", () => {
console.log("socket has connected");
socket.emit("message", {
type: "test",
content: {
msg: "test message",
userId: JSON.parse(localStorage.getItem("user"))._id,
},
});
});
socket.on("message", (msg) => {
console.log("client recieved the message", msg);
});
socket.io.on("reconnect", (attempt) => {
console.log("socket reconnection success");
});
Dockerfile //客户端
FROM node:current-alpine as build
WORKDIR /app
COPY package*.json /app/
RUN npm install
RUN npm ci --production
COPY . .
RUN npm run build
FROM nginx:stable
COPY --from=build /app/build/ /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/conf.d/default.conf
我终于通过在套接字初始化中省略 url 来让它工作了,如下所示:
在 socketio.js
export let socket = io({
path: "/socket.io/",
auth: { token: "token" },
query: { userId: user ? JSON.parse(localStorage.getItem("user"))._id : "" },
autoConnect: false,
transports: ["websocket"],
withCredentials: true,
});
截至目前,我不确定为什么我不能像开发中那样点击 url,即将其指向 nginx 服务器,任何见解都将不胜感激,谢谢。