使用 MERN 堆栈和 socket.io 进行私人聊天
Posted
技术标签:
【中文标题】使用 MERN 堆栈和 socket.io 进行私人聊天【英文标题】:Private chat using MERN stack and socket.io 【发布时间】:2020-12-22 10:22:48 【问题描述】:我正在使用 MERN 堆栈和 socket.io 开发一个私人聊天应用程序。
我能够成功地向特定用户发送私人消息,但无法包含消息发件人以显示给两个用户。
客户
export default function Chat( users )
const [activeUser, setActiveUser] = useState('');
const [currentUser, setCurrentUser] = useState(null);
const [filteredList, setFilteredList] = useState([]);
const [message, setMessage] = useState('');
const [chats, setChats] = useState([]);
useEffect(() =>
const jwt = isAuthenticated().user;
setCurrentUser(jwt);
config.socket;
config.socket.on('isOnline', (data) =>
console.log(data);
);
, []);
useEffect(() =>
const list = users.filter(user => currentUser ? user._id !== currentUser._id : user._id);
setFilteredList(list);
, [currentUser]);
useEffect(() =>
config.socket.on('chat', (data) =>
setChats([...chats, data]);
);
, []);
const changeActiveUser = (e, user) =>
e.preventDefault();
console.log(`changeActiveUser $JSON.stringify(user)`);
setActiveUser(user);
;
const handleClick = e =>
e.preventDefault();
const msg =
socketId: activeUser.socketId,
to: activeUser._id,
toUser: activeUser.username,
message: message,
from: currentUser._id
// config.socket.emit('join', id: activeUser.socketId, username: activeUser.username)
console.log(`Private MSG $JSON.stringify(msg)`);
config.socket.emit('private', msg);
setMessage('');
return (
<>
<div className='container'>
<div className='row'>
<div className='col-3 leftSide'>
filteredList.map((user) => (
<li key=user._id className=`list $user._id === activeUser._id ? 'active' : ''` onClick=e => changeActiveUser(e, user)>
<img className='userImg' src=user.gender === 'Female' ? '/female.jpg' : '/male.jpg' /> user.name <small> (user.username) <span>user.online ? 'online' : 'offline'</span></small>
</li>
))
</div>
<div className='col-9 rightSide'>
<div className='row'>
<div className='col rightTop'>
<h1>activeUser.username ? `$activeUser.username ($activeUser._id)` : 'Start a chat!'</h1>
<ul>
chats && chats.map((chat, i) => (
<li key=i>
<span>activeUser._id === chat.from ? <span style= float: 'left' >`$activeUser.username: $chat.message`</span> : <span style= float: 'right' >`Me: $chat.message`</span></span>
/* <div>activeUser._id === chat.to ? <div style= float: 'right' >`Me: $chat.message`</div> : ''</div> */
</li>
))
</ul>
</div>
</div>
<hr />
activeUser && (
<div className='row rightBottomContainer'>
<div className='rightBottomInput'>
<input value=message type='text' onChange=(e) => setMessage(e.target.value) placeholder=' Enter your chat...' />
</div>
<div className='rightBottomButton'>
<button onClick=(e) => handleClick(e) type='submit'>Send</button>
</div>
</div>
)
</div>
</div>
</div>
</>
);
服务器
const users = ;
io.on('connection', (socket) =>
console.log(`$socket.id connected`);
socket.on('signin', (data) =>
users[data.username] = data.socketId;
socket.emit('isOnline', userId: data.userId, online: true );
);
console.log(`USERS: $JSON.stringify(users)`);
// socket.on('join', (data) =>
// console.log(`JOIN: $JSON.stringify(data)`);
// socket.join(data.id);
// );
socket.on('private', (msg) =>
console.log(`users[msg.toUser] $users[msg.toUser] === msg.socketId $msg.socketId`);
if (users[msg.toUser] === msg.socketId)
console.log(msg);
io.to(msg.socketId).emit('chat', msg);
);
socket.on('disconnect', () =>
console.log(`$socket.id disconnected`);
);
);
我需要帮助来包含发件人以及要显示给两个用户的消息。而且我还想正确附加消息,因为上面的代码覆盖了之前的消息。
【问题讨论】:
将两个用户添加到房间名称 user1-user2 然后发送到房间。 socket.io/docs/v3/emit-cheatsheet 【参考方案1】:您可以创建一个包含 2 个用户的房间。每次您想开始私人聊天时。我只是使用类似下面的代码来实现它。
假设我们有一个id = 1
的用户想要向id = 2
的用户发送一条消息。所以我们创建了一个房间名称1-2
,所以当第一个用户想向第二个用户发送消息时,你必须在客户端初始化socket.io时将1-2
添加到查询中:
socket = socketIOClient(ENDPOINT,
query:
room: "1-2",
,
);
现在您在服务器上知道用户想要连接到哪个房间。因此您可以使用以下代码将房间添加到您的套接字:
io.use(async function(socket, next)
socket.room = socket.handshake.query.room;
return next();
所以现在你可以使用 socket.io 的room
功能将消息发送给发送者和接收者,如下所示:
socket.on('private', (msg) =>
socket.broadcast
.to(socket.room)
.emit("chat", msg)
);
整个服务器代码将是这样的:
io.use(function(socket, next)
socket.room = socket.handshake.query.room;
return next();
)
.on("connection", function(socket)
socket.on('private', (msg) =>
socket.broadcast
.to(socket.room)
.emit("chat", msg)
);
【讨论】:
以上是关于使用 MERN 堆栈和 socket.io 进行私人聊天的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Socket.io 中与 Heroku 服务器建立 Socket 连接?
当同时使用 GraphQL 时,Nodejs 和 Express 在 MERN 堆栈 Web 应用程序中的作用是啥?
Node.js + Socket.io 超出最大调用堆栈大小