使用 kubernetes 和微服务的 nodejs 上的 socket.io 问题
issue with socket.io on nodejs with kubernetes and microservices
很长一段时间我不必在这里写 post。我想我真的被困住了......
很久以前,我构建了一个基于 React 和 Express 的单体应用程序,它正在处理与 socket.io 的聊天。我记得我确实有点挣扎,但最后我成功了。
我现在正在使用 kubernetes(在 GKE 上)将同一个应用程序重新转换为微服务,在构建聊天后端和前端之后,我就是无法进行聊天。 socket.io 实例似乎以某种方式未连接。我尝试了很多不同的事情,现在我正在寻求帮助。我将在下面分享暗示它的代码部分。
使用 EXPRESS 聊天后端:
我正在声明一个中间件以将 io 作为 req.io 传递,以便能够在特定端点中使用。这部分工作正常(至少在我看来)
require("express-async-errors")
const express = require("express")
const helmet = require("helmet")
const socket = require("socket.io")
const http = require("http")
const compression = require("compression")
const bodyParser = require("body-parser")
const cookieSession = require("cookie-session")
const cookieParser = require("cookie-parser")
// IMPORT ROUTES
const routes = require("./routes")
// IMPORT MIDDLWARES
const Import = require("@archsplace/archsplace_commun")
const isError = Import("middlewares", "isError")
const isCurrentUser = Import("middlewares", "isCurrentUser")
const { NotFoundError } = Import("factory", "errors")
// LAUNCH EXPRESS
const app = express()
const server = http.createServer(app)
const io = socket(server)
const secure = process.env.NODE_ENV !== "test"
// USE MAIN MIDDLWWARE
app.set("trust proxy", true)
app.use(helmet())
app.disable("x-powered-by")
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cookieSession({ signed: false, secure }))
app.use(isCurrentUser)
app.use(cookieParser())
app.use(compression())
app.use((req, res, next) => {
req.io = io
next()
})
// USE ROUTES
routes.map(route => app.use(route.url, route.path))
app.all("*", async (req, res) => {
throw new NotFoundError()
})
// USE CUSTOM MIDDLWWARE
app.use(isError)
module.exports = server
然后我有一个端点来发出聊天事件,它与我用来 POST 我的 mongoDB 数据库中的消息的相同端点。我认为这部分以某种方式起作用,但不确定它到底在哪里发射
发出套接字事件的终点
const express = require("express")
const db = require("mongoose")
// DATABASE AND LIBRARIES
const Import = require("@archsplace/archsplace_commun")
const isAuthenticated = Import("middlewares", "isAuthenticated")
const isActivated = Import("middlewares", "isActivated")
const Chat = Import("models", "Chat", "chat")
const Room = Import("models", "ChatRoom", "chat")
// EVENTS
const { NatsWrapper } = require("../../../services/natsWrapper")
const { RoomUpdatedPub } = require("../../../events/publishers/roomUpdatedPub")
const { ChatCreatedPub } = require("../../../events/publishers/chatCreatedPub")
// VALIDATES
const { BadRequestError, DatabaseConnectionError } = Import("factory", "errors")
const router = express.Router()
// @route POST api/chat/private/message/:roomId
// @desc Post Chat message by chatroom id
// @access Private
router.post("/:roomId", isAuthenticated, isActivated, async (req, res) => {
// DEFINE QUERIES
let chat
const { message, avatar } = req.body
const { roomId } = req.params
// ENSURE ROOM EXIST FOR USER
const room = await Room.findOne({ $and: [{ _id: roomId }, { _users: { $elemMatch: { _user: req.user._id } } }] })
if (!room) {
throw new BadRequestError("This chatroom doesn't exist")
}
// CREATE CHAT
const chatFields = {
message,
_emitter: req.user._id,
_chatId: roomId
}
// EMIT TO SOCKET
req.io.emit(roomId, {
...chatFields,
avatar: avatar,
read: 1,
role: req.user.authorities
})
// HANDLE MONGODB TRANSACTIONS
const SESSION = await db.startSession()
try {
// CREATE CHAT
await SESSION.startTransaction()
chat = await new Chat(chatFields).save()
await room.set({ lastUpdated: Date.now() }).save()
await new RoomUpdatedPub(NatsWrapper.client()).publish(room)
await new ChatCreatedPub(NatsWrapper.client()).publish(chat)
await SESSION.commitTransaction()
// RETURN AND FINALIZE ENDPOINT
res.status(201).json(chat)
} catch (e) {
// CATCH ANY ERROR DUE TO TRANSACTION
await SESSION.abortTransaction()
console.error(e)
throw new DatabaseConnectionError()
} finally {
// FINALIZE SESSION
SESSION.endSession()
}
})
module.exports = router
入口 NGINX CONGIS
这可能是错误的,我在互联网上看到我们需要使用此注释 nginx.ingress.kubernetes.io/websocket-services 并且我将其归因于我建立聊天的服务器(以及我所在的位置)使用 socket.io)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/permanent-redirect-code: "301"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
# SOCKET CONFIGURATIONS
nginx.ingress.kubernetes.io/websocket-services: "chat-srv"
nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"
nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
spec:
rules:
- host: www.archsplace.dev
http:
paths:
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-website-srv
servicePort: 3000
- host: architects.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-architects-srv
servicePort: 3000
- host: users.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-users-srv
servicePort: 3000
- host: partners.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-partners-srv
servicePort: 3000
- host: admin.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-admin-srv
servicePort: 3000
- host: business.archsplace.dev
http:
paths:
- path: /?(.*)
backend:
serviceName: client-business-srv
servicePort: 3000
然后在客户端,我在我的 React 应用程序上使用库 socket.io-client。
我声明 IO 库的客户端实用程序
自从我使用 architects.archsplace.dev,我假设聊天服务器只能在 /api/chat 可用,因为它是在入口 nginx 上定义的,但我不确定..
import io from "socket.io-client"
export const socket = io(`${window.location.host}/api/chat`, {
reconnect: true
})
然后我用聊天构建了一个 UI,我实际上正在尝试接收聊天信息并将其存储到反应状态:
使用影响组件来加载套接字
在这里您还可以看到使用效果我正在使用roomId连接到我之前在后端部分发出的同一事件。 (这是在整体上工作但不是在这里)
import React, { useState, useEffect } from "react"
import { connect } from "react-redux"
import Timestamp from "react-timestamp"
// IMPORT ACTIONS
import { sendMessage, getMessages } from "@actions/chatActions"
// IMPORT COMPONENTS
import ChatMessage from "./ChatMessage"
// IMPORT UTILS
import { socket, isEmpty, imageRender } from "@utils"
const ChatRoom = ({ sendMessage, getMessages, classes, room, user, chat: { messages } }) => {
// HOOKS
const [state, setState] = useState({
message: "",
messages: [],
errors: {},
typing: false,
trigger: false,
isInteracted: false,
page: 0,
limit: 20
})
const target = room.users.find(({ _id }) => _id !== user._id)
const isOnline = Math.floor(Date.now() - new Date(target.lastConnectionDate).getTime() / 1000) && target.isOnline
// USE EFFECT
useEffect(() => {
getMessages(state.page, state.limit, room._id)
}, [getMessages, state.page, state.limit, room._id])
useEffect(() => {
const handleMessageSocket = () => {
const addMessage = data => setState(prevStates => ({ ...prevStates, messages: [...state.messages, data] }))
socket.on(room._id, data => addMessage(data))
}
const clearMessageSocket = () => {
socket.off(room._id)
setState(prevStates => ({ ...prevStates, messages: [] }))
}
// LOAD DATA FROM REDUCER
setState(prevStates => ({ ...prevStates, messages }))
// LOAD SOCKETS
handleMessageSocket()
return () => clearMessageSocket()
}, [room._id, state.messages, messages])
// HANDLE FUNCTIONS
const handleMessage = e => setState(prevStates => ({ ...prevStates, message: e.target.value }))
const clearMessage = () => setState(prevStates => ({ ...prevStates, message: "" }))
const handleSubmit = e => {
e.preventDefault()
const chatMessage = { message: state.message, avatar: imageRender(user.avatar, "tr:n-user_avatar_small") }
!isEmpty(state.message) && sendMessage(chatMessage, room._id)
clearMessage()
}
// RENDER CHATROOM ITEM
const renderAvatar = () => {
return (
<div className={classes.chatRoomItemAvatar}>
<img src={imageRender(target.avatar, "tr:n-user_avatar_small")} alt={target.name} />
{isOnline && <div className={classes.chatRoomItemActive} />}
</div>
)
}
const renderInfo = () => {
return (
<div className={classes.chatRoomItemInfo}>
<h3>{target.name}</h3>
<p>
<i>access_time</i>
<Timestamp className="request-item-timestamp" relative date={target.lastConnectionDate} autoUpdate />
</p>
</div>
)
}
const renderChatItem = () => {
return (
<div className={classes.chatRoomItem}>
{renderAvatar()}
{renderInfo()}
</div>
)
}
// RENDER MESSAGE AREA
const renderMessages = () => {
return <div className={classes.chatMessages}>{JSON.stringify(state.messages.map(i => i.message))}</div>
}
// RENDER INPUT AREA
const renderInput = () => {
return (
<form className={classes.chatInputWrapper} autoComplete="off" onSubmit={e => handleSubmit(e)}>
<div className={classes.chatInput}>
<input type="text" placeholder="Message" value={state.message} onChange={handleMessage} />
<button type="submit">
<i>reply</i>
</button>
</div>
</form>
)
}
// MAIN
return (
<div className={classes.chatRoom}>
{renderChatItem()}
{renderMessages()}
{renderInput()}
</div>
)
}
const mapStateToProps = state => ({
chat: state.chat
})
export default connect(mapStateToProps, { sendMessage, getMessages })(ChatRoom)
所以如果有人遇到过同样的问题,并且知道我可能做错了什么,我完全被困住了。我什至尝试设置一个 redis 服务并通过 redis io 适配器传递套接字,但也没有用...
我在那里为那些可能像我一样挣扎的人找到了解决方案...我认为它有点老套,但效果很好。
我在前面观察到套接字一直在 /socket.io/.... 下触发,如果您查看我的入口 nginx,它会查看我的 React 应用程序,并且return 可能是一个 404 页面。
所以我使用以下代码强制我的 chat-srv 出现在这个特定端点上:
- path: /socket.io/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
然后一旦我这样做了,它实际上是在查看我的聊天后端并解决了。我还需要指定我使用 socket.io
的 2.2.0 版本
我试过版本 3,但没用。
很长一段时间我不必在这里写 post。我想我真的被困住了...... 很久以前,我构建了一个基于 React 和 Express 的单体应用程序,它正在处理与 socket.io 的聊天。我记得我确实有点挣扎,但最后我成功了。
我现在正在使用 kubernetes(在 GKE 上)将同一个应用程序重新转换为微服务,在构建聊天后端和前端之后,我就是无法进行聊天。 socket.io 实例似乎以某种方式未连接。我尝试了很多不同的事情,现在我正在寻求帮助。我将在下面分享暗示它的代码部分。
使用 EXPRESS 聊天后端:
我正在声明一个中间件以将 io 作为 req.io 传递,以便能够在特定端点中使用。这部分工作正常(至少在我看来)
require("express-async-errors")
const express = require("express")
const helmet = require("helmet")
const socket = require("socket.io")
const http = require("http")
const compression = require("compression")
const bodyParser = require("body-parser")
const cookieSession = require("cookie-session")
const cookieParser = require("cookie-parser")
// IMPORT ROUTES
const routes = require("./routes")
// IMPORT MIDDLWARES
const Import = require("@archsplace/archsplace_commun")
const isError = Import("middlewares", "isError")
const isCurrentUser = Import("middlewares", "isCurrentUser")
const { NotFoundError } = Import("factory", "errors")
// LAUNCH EXPRESS
const app = express()
const server = http.createServer(app)
const io = socket(server)
const secure = process.env.NODE_ENV !== "test"
// USE MAIN MIDDLWWARE
app.set("trust proxy", true)
app.use(helmet())
app.disable("x-powered-by")
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())
app.use(cookieSession({ signed: false, secure }))
app.use(isCurrentUser)
app.use(cookieParser())
app.use(compression())
app.use((req, res, next) => {
req.io = io
next()
})
// USE ROUTES
routes.map(route => app.use(route.url, route.path))
app.all("*", async (req, res) => {
throw new NotFoundError()
})
// USE CUSTOM MIDDLWWARE
app.use(isError)
module.exports = server
然后我有一个端点来发出聊天事件,它与我用来 POST 我的 mongoDB 数据库中的消息的相同端点。我认为这部分以某种方式起作用,但不确定它到底在哪里发射
发出套接字事件的终点
const express = require("express")
const db = require("mongoose")
// DATABASE AND LIBRARIES
const Import = require("@archsplace/archsplace_commun")
const isAuthenticated = Import("middlewares", "isAuthenticated")
const isActivated = Import("middlewares", "isActivated")
const Chat = Import("models", "Chat", "chat")
const Room = Import("models", "ChatRoom", "chat")
// EVENTS
const { NatsWrapper } = require("../../../services/natsWrapper")
const { RoomUpdatedPub } = require("../../../events/publishers/roomUpdatedPub")
const { ChatCreatedPub } = require("../../../events/publishers/chatCreatedPub")
// VALIDATES
const { BadRequestError, DatabaseConnectionError } = Import("factory", "errors")
const router = express.Router()
// @route POST api/chat/private/message/:roomId
// @desc Post Chat message by chatroom id
// @access Private
router.post("/:roomId", isAuthenticated, isActivated, async (req, res) => {
// DEFINE QUERIES
let chat
const { message, avatar } = req.body
const { roomId } = req.params
// ENSURE ROOM EXIST FOR USER
const room = await Room.findOne({ $and: [{ _id: roomId }, { _users: { $elemMatch: { _user: req.user._id } } }] })
if (!room) {
throw new BadRequestError("This chatroom doesn't exist")
}
// CREATE CHAT
const chatFields = {
message,
_emitter: req.user._id,
_chatId: roomId
}
// EMIT TO SOCKET
req.io.emit(roomId, {
...chatFields,
avatar: avatar,
read: 1,
role: req.user.authorities
})
// HANDLE MONGODB TRANSACTIONS
const SESSION = await db.startSession()
try {
// CREATE CHAT
await SESSION.startTransaction()
chat = await new Chat(chatFields).save()
await room.set({ lastUpdated: Date.now() }).save()
await new RoomUpdatedPub(NatsWrapper.client()).publish(room)
await new ChatCreatedPub(NatsWrapper.client()).publish(chat)
await SESSION.commitTransaction()
// RETURN AND FINALIZE ENDPOINT
res.status(201).json(chat)
} catch (e) {
// CATCH ANY ERROR DUE TO TRANSACTION
await SESSION.abortTransaction()
console.error(e)
throw new DatabaseConnectionError()
} finally {
// FINALIZE SESSION
SESSION.endSession()
}
})
module.exports = router
入口 NGINX CONGIS
这可能是错误的,我在互联网上看到我们需要使用此注释 nginx.ingress.kubernetes.io/websocket-services 并且我将其归因于我建立聊天的服务器(以及我所在的位置)使用 socket.io)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/permanent-redirect-code: "301"
nginx.ingress.kubernetes.io/from-to-www-redirect: "true"
# SOCKET CONFIGURATIONS
nginx.ingress.kubernetes.io/websocket-services: "chat-srv"
nginx.ingress.kubernetes.io/proxy-send-timeout: "1800"
nginx.ingress.kubernetes.io/proxy-read-timeout: "1800"
spec:
rules:
- host: www.archsplace.dev
http:
paths:
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-website-srv
servicePort: 3000
- host: architects.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-architects-srv
servicePort: 3000
- host: users.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-users-srv
servicePort: 3000
- host: partners.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-partners-srv
servicePort: 3000
- host: admin.archsplace.dev
http:
paths:
- path: /auth/?(.*)
backend:
serviceName: auth-srv
servicePort: 3000
- path: /api/account/?(.*)
backend:
serviceName: account-srv
servicePort: 3000
- path: /api/architect/?(.*)
backend:
serviceName: architect-srv
servicePort: 3000
- path: /api/chat/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
- path: /?(.*)
backend:
serviceName: client-admin-srv
servicePort: 3000
- host: business.archsplace.dev
http:
paths:
- path: /?(.*)
backend:
serviceName: client-business-srv
servicePort: 3000
然后在客户端,我在我的 React 应用程序上使用库 socket.io-client。
我声明 IO 库的客户端实用程序
自从我使用 architects.archsplace.dev,我假设聊天服务器只能在 /api/chat 可用,因为它是在入口 nginx 上定义的,但我不确定..
import io from "socket.io-client"
export const socket = io(`${window.location.host}/api/chat`, {
reconnect: true
})
然后我用聊天构建了一个 UI,我实际上正在尝试接收聊天信息并将其存储到反应状态:
使用影响组件来加载套接字
在这里您还可以看到使用效果我正在使用roomId连接到我之前在后端部分发出的同一事件。 (这是在整体上工作但不是在这里)
import React, { useState, useEffect } from "react"
import { connect } from "react-redux"
import Timestamp from "react-timestamp"
// IMPORT ACTIONS
import { sendMessage, getMessages } from "@actions/chatActions"
// IMPORT COMPONENTS
import ChatMessage from "./ChatMessage"
// IMPORT UTILS
import { socket, isEmpty, imageRender } from "@utils"
const ChatRoom = ({ sendMessage, getMessages, classes, room, user, chat: { messages } }) => {
// HOOKS
const [state, setState] = useState({
message: "",
messages: [],
errors: {},
typing: false,
trigger: false,
isInteracted: false,
page: 0,
limit: 20
})
const target = room.users.find(({ _id }) => _id !== user._id)
const isOnline = Math.floor(Date.now() - new Date(target.lastConnectionDate).getTime() / 1000) && target.isOnline
// USE EFFECT
useEffect(() => {
getMessages(state.page, state.limit, room._id)
}, [getMessages, state.page, state.limit, room._id])
useEffect(() => {
const handleMessageSocket = () => {
const addMessage = data => setState(prevStates => ({ ...prevStates, messages: [...state.messages, data] }))
socket.on(room._id, data => addMessage(data))
}
const clearMessageSocket = () => {
socket.off(room._id)
setState(prevStates => ({ ...prevStates, messages: [] }))
}
// LOAD DATA FROM REDUCER
setState(prevStates => ({ ...prevStates, messages }))
// LOAD SOCKETS
handleMessageSocket()
return () => clearMessageSocket()
}, [room._id, state.messages, messages])
// HANDLE FUNCTIONS
const handleMessage = e => setState(prevStates => ({ ...prevStates, message: e.target.value }))
const clearMessage = () => setState(prevStates => ({ ...prevStates, message: "" }))
const handleSubmit = e => {
e.preventDefault()
const chatMessage = { message: state.message, avatar: imageRender(user.avatar, "tr:n-user_avatar_small") }
!isEmpty(state.message) && sendMessage(chatMessage, room._id)
clearMessage()
}
// RENDER CHATROOM ITEM
const renderAvatar = () => {
return (
<div className={classes.chatRoomItemAvatar}>
<img src={imageRender(target.avatar, "tr:n-user_avatar_small")} alt={target.name} />
{isOnline && <div className={classes.chatRoomItemActive} />}
</div>
)
}
const renderInfo = () => {
return (
<div className={classes.chatRoomItemInfo}>
<h3>{target.name}</h3>
<p>
<i>access_time</i>
<Timestamp className="request-item-timestamp" relative date={target.lastConnectionDate} autoUpdate />
</p>
</div>
)
}
const renderChatItem = () => {
return (
<div className={classes.chatRoomItem}>
{renderAvatar()}
{renderInfo()}
</div>
)
}
// RENDER MESSAGE AREA
const renderMessages = () => {
return <div className={classes.chatMessages}>{JSON.stringify(state.messages.map(i => i.message))}</div>
}
// RENDER INPUT AREA
const renderInput = () => {
return (
<form className={classes.chatInputWrapper} autoComplete="off" onSubmit={e => handleSubmit(e)}>
<div className={classes.chatInput}>
<input type="text" placeholder="Message" value={state.message} onChange={handleMessage} />
<button type="submit">
<i>reply</i>
</button>
</div>
</form>
)
}
// MAIN
return (
<div className={classes.chatRoom}>
{renderChatItem()}
{renderMessages()}
{renderInput()}
</div>
)
}
const mapStateToProps = state => ({
chat: state.chat
})
export default connect(mapStateToProps, { sendMessage, getMessages })(ChatRoom)
所以如果有人遇到过同样的问题,并且知道我可能做错了什么,我完全被困住了。我什至尝试设置一个 redis 服务并通过 redis io 适配器传递套接字,但也没有用...
我在那里为那些可能像我一样挣扎的人找到了解决方案...我认为它有点老套,但效果很好。
我在前面观察到套接字一直在 /socket.io/.... 下触发,如果您查看我的入口 nginx,它会查看我的 React 应用程序,并且return 可能是一个 404 页面。
所以我使用以下代码强制我的 chat-srv 出现在这个特定端点上:
- path: /socket.io/?(.*)
backend:
serviceName: chat-srv
servicePort: 3000
然后一旦我这样做了,它实际上是在查看我的聊天后端并解决了。我还需要指定我使用 socket.io
的 2.2.0 版本我试过版本 3,但没用。