我有一个react前端和nodejs后端,使用nginx进行服务和负载均衡。当我在本地运行nginx和npm运行dev时,我的设置工作正常,但当我通过docker compose通过docker容器运行时,web sockets无法连接。在控制台中:
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 //client
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
型
1条答案
按热度按时间wtzytmuj1#
最后,我通过在套接字初始化中省略url来让它工作,如下所示:
在 * socketio.js * 中
字符串
到目前为止,我不确定为什么我不能像在开发中那样点击url,即将其指向nginx服务器。我的想法是它不能点击localhost,因为它应该由它的服务名称引用,所以我必须用不同的url点击nginx图像,我只是不确定那会是什么,因为它是在前端Dockerfile中作为多阶段构建而构建的,而不是在Docker中列为服务-compose. yml。是否将套接字URL指向前端图像服务名称?听起来不对...或者我可以单独构建nginx和前端,并将nginx作为docker-compose.yml中的服务列出,并在该服务名称处访问它,但我认为在前端映像中的多阶段构建是最佳实践。任何见解都将受到赞赏,谢谢。
--编辑
进一步考虑,我相信来自我的react应用程序的请求在前端图像构建期间被设置为命中nginx,并且nginx.conf的服务器指令中的位置块拾取套接字连接的路径,所以这就是为什么我可以将url留空,只添加路径。