NodeJS 通过www.example.com加入聊天室Socket.io

lsmepo6l  于 2023-01-25  发布在  Node.js
关注(0)|答案(1)|浏览(296)

我试图创建一种房间系统的消息传递系统,我正在与socket.io的一个React项目,它似乎没有连接正确。
这是相当复杂的,所以我会带您通过一个用例。
1.用户登录和它的问候与此页面:

如您所见,我的用户已在左下角登录
1.此用户现在要向某人发送消息让我们使用test,因为test是视图中的当前配置文件
1.用户单击配置文件视图右上角的消息按钮,这会将他们带到此屏幕:

他们现在可以向他们发送他们想要发送的任何消息
这就是现在的问题所在。很明显,测试会想看看管理员发送给他们什么,这就是我想要一个房间系统的地方。这样,当登录的用户点击用户发送消息时,它会创建一个房间,在那里两个用户可以互相发送消息。我曾试图通过www.example.com实现这socket.io因为我以前的GET和POST请求版本不是实时的。到目前为止你只能发送消息,用户之间没有任何种类的来回。
通过我的测试,我做了一个房间ID,并将其记录到控制台,如下所示:

joined room: admin admin_test test
{
  sender: 'admin admin',
  recipient: 'test test',
  message: 'a',
  time: '17:47',
  room: 'admin admin_test test'
}
joined room: admin admin_test test
{
  sender: 'test test',
  recipient: 'admin admin',
  message: 'a',
  time: '17:47',
  room: 'admin admin_test test'
}

这确实表明消息正在发送,并且它们在同一个房间ID下。我不确定他们为什么不接收消息。我希望有任何解决方案,以便这两个人可以在彼此之间来回发送消息。
下面是管理套接字的后端:

const { Server } = require("socket.io");

const socket = (server) => {
  const io = new Server(server, {
    cors: {
      origin: "*",
      methods: ["GET", "POST"],
    },
  });

  //On connection
  io.on('connection', socket => {    
    //On join room
    socket.on('join', room => {
       socket.join(room);

        console.log('joined room: ' + room);
    });

    //On message send
    socket.on('send_message', (data) => {
      //Log message
      console.log(data);

      //Emit to recipient
      io.to(data.room).emit('receive_message', data);
    });
  });
};

module.exports = socket;

处理消息传递的客户端:

import { useEffect, useState, useRef } from 'react';
import io from 'socket.io-client';

import { ArrowLongUpIcon } from '@heroicons/react/24/outline';

export default function Message({sender, recipient, profilePicture, roomId}) {
    const socket = io('http://localhost:8080');

    const [message, setMessage] = useState('');
    const [messages, setMessages] = useState([]);

    const bottomRef = useRef(null);
    
    //Sends message to server
    const sendMessage = async () => {
        //If input isnt empty
        if (message !== '') {
            //Formats message
            const messageData = {
                sender: sender,
                recipient: recipient,
                message: message,
                time: new Date().getHours() + ':' + new Date().getMinutes(),
                room: roomId
            };

            //Sends to back end
            await socket.emit('send_message', messageData);
            //Shows previously sent message
            setMessages((list) => [...list, messageData]);    
            
            //Clears input
            setMessage('');
        };
    };

    useEffect(() => {           
        //Receive message from back-end
        socket.on('receive_message', (data) => {
            console.log(data);
            console.log(roomId);
            //If message is for this room
            if (data.room === roomId) {
                console.log(data);
                //Show message
                setMessages((list) => [...list, data]);
            }
        });
    }, [roomId]);

    useEffect(() => {
        // Scroll to bottom every time messages change
        bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
      }, [messages]);

    return (
        /* Messages */
        <div class="flex flex-col h-full max-h-[750px] w-full px-4 py-6">
            {/* Message list */}
            <div class="h-full overflow-y-scroll pb-4">
                <p class="text-center italic text-gray-400">Chat started with: <span class="font-semibold">{recipient}</span></p>
                <div class="grid grid-cols-12">
                    {/* Individual message */}
                    {messages.map((messageContent, index) => {
                        return (
                            messageContent.sender === sender ? (
                                /* Sender */
                                <div key={index} class="col-start-6 col-end-13 p-2 rounded-lg">
                                    <div class="flex justify-start flex-row-reverse">        
                                        {/* Message content */}
                                        <div class="flex flex-col space-y-1.5">
                                            <div class="relative mr-3 text-sm bg-blue-100 py-2 px-4 shadow rounded-xl">
                                                <p ref={bottomRef}>{messageContent.message}</p>
                                            </div>

                                            <p class="text-xs text-gray-400 italic text-right mr-4">{messageContent.time}</p>
                                        </div>
                                    </div>

                                </div>
                            ) : (
                                
                                /* Recipient */
                                <div key={index} class="col-start-1 col-end-8 p-3 rounded-lg">
                                    <div class="flex flex-row">
                                        <div class="flex items-center justify-center h-10 w-10 flex-shrink-0">
                                            <img
                                                src={'http://localhost:8080/public/' + profilePicture}
                                                alt="Profile picture"
                                                class="rounded-full"
                                            ></img>
                                        </div>

                                        <div class="flex flex-col space-y-2">
                                            <div class="relative ml-3 text-sm bg-white py-2 px-4 shadow rounded-xl">
                                                <p ref={bottomRef}>{messageContent.message}</p>
                                            </div>

                                            <p class="text-xs text-gray-400 italic text-right ml-4">{messageContent.time}</p>
                                        </div>
                                    </div>
                                </div>
                            )
                        )
                    })}
                </div>
            </div>

            {/* Input */}
            <div class="flex flex-row items-center pt-3">
                <input 
                    type="text" 
                    placeholder="Enter your message"
                    value={message}
                    onChange={(e) => setMessage(e.target.value)}
                    onKeyPress={(e) => {
                        e.key === 'Enter' && sendMessage();
                    }}
                    class="w-full h-10 px-4 text-sm  rounded-3xl focus:outline-none focus:border-blue-300 focus:ring focus:ring-opacity-40 focus:ring-blue-200">
                </input>

                <div class="ml-6">
                    <button 
                        onClick={sendMessage}
                        class="flex items-center justify-center h-10 w-10 rounded-full bg-gray-200 hover:bg-gray-300 text-blue-600"
                    >
                        <svg class="w-5 h-5 transform rotate-90 -mr-px"
                            fill="none"
                            stroke="currentColor"
                            viewBox="0 0 24 24"
                            xmlns="http://www.w3.org/2000/svg">
                        <path stroke-linecap="round"
                                stroke-linejoin="round"
                                stroke-width="2"
                                d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"></path>
                        </svg>
                    </button>
                </div>
            </div>

            {/* Back to top button */}
            <div class="flex justify-center my-5">
                <button
                    onClick={() => {document.documentElement.scrollTop = 0;}}
                    class="inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
                >
                    Back to top

                    <ArrowLongUpIcon class="h-4 w-4" aria-hidden="true" />
                </button>
            </div>
        </div>
    );
};

和消息的父组件,处理其打开和关闭,请不要这个文件是非常大的,所以我删除了任何不相关的,但一些混乱仍然存在:

const socket = io('http://localhost:8080');

    const roomId = [sender, profileFirstName + " " +  profileLastName].sort().join('_');

    const messageHandler = () => {
        socket.emit('join', roomId);

        setRenderMessage(!renderMessage);
    };

    return (
        <div class="flex">
            <SideBar />

            <div className="flex w-screen h-auto">
                <div className="flex min-w-0 flex-1 flex-col overflow-hidden">
                    <div className="relative z-0 flex flex-1 overflow-hidden">
                        <main className="relative z-0 flex-1 overflow-y-auto focus:outline-none xl:order-last">
                            {/* Breadcrumb */}
                            <article>
                                {/* Profile header */}
                                <div>
                                    <div>
                                        <img
                                            className="h-32 w-full object-cover lg:h-48"
                                            src={profile.coverImageUrl}
                                            alt=""
                                        />
                                    </div>
                                    <div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
                                        <div className="-mt-12 sm:-mt-16 sm:flex sm:items-end sm:space-x-5">
                                            <div className="flex">
                                                <img
                                                    className="h-24 w-24 rounded-full ring-4 ring-white sm:h-32 sm:w-32"
                                                    src={
                                                        "http://localhost:8080/public/" +
                                                        profile.profile_picture
                                                    }
                                                    alt=""
                                                />
                                            </div>
                                            <div className="mt-6 sm:flex sm:min-w-0 sm:flex-1 sm:items-center sm:justify-end sm:space-x-6 sm:pb-1">
                                                <div className="mt-6 min-w-0 flex-1 sm:hidden 2xl:block">
                                                    <h1 className="truncate text-2xl font-bold text-gray-900">
                                                        {profile.name}
                                                    </h1>
                                                </div>
                                                <div className="justify-stretch mt-6 flex flex-col space-y-3 sm:flex-row sm:space-y-0 sm:space-x-4">
                                                    <button
                                                        type="button"
                                                        onClick={messageHandler}
                                                        className="inline-flex justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
                                                    >
                                                        <EnvelopeIcon
                                                            className="-ml-1 mr-2 h-5 w-5 text-gray-400"
                                                            aria-hidden="true"
                                                        />
                                                        {renderMessage ? (
                                                            <span>
                                                                Close Message
                                                            </span>
                                                        ) : (
                                                            <span>Message</span>
                                                        )}
                                                    </button>

                                                    {/* <button
                                                        type="button"
                                                        className="inline-flex justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-600 focus:ring-offset-2"
                                                    >
                                                        <PhoneIcon className="-ml-1 mr-2 h-5 w-5 text-gray-400" aria-hidden="true" />
                                                        <span>Call</span>
                                                    </button> */}
                                                </div>
                                            </div>
                                        </div>
                                        <div className="mt-6 hidden min-w-0 flex-1 sm:block 2xl:hidden">
                                            <h1 className="truncate text-2xl font-bold text-gray-900">
                                                {profile.name}
                                            </h1>
                                        </div>
                                    </div>
                                </div>                            

                                {/* If state is true render Messaging component */}
                                {renderMessage ? (
                                    <Message
                                        sender={sender}
                                        recipient={profileFirstName + " " +  profileLastName}
                                        profilePicture={profileProfilePicture}
                                        roomId={roomId}
                                    />
                                ) : (
                                    <>
                                        {/* Description list */}
                                        <div className="mx-auto mt-6 max-w-5xl px-4 sm:px-6 lg:px-8">
                                            <dl className="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2">
                                                {Object.keys(
                                                    profile.fields
                                                ).map((field) => (
                                                    <div
                                                        key={field}
                                                        className="sm:col-span-1"
                                                    >
                                                        <dt className="text-sm font-medium text-gray-500">
                                                            {field}
                                                        </dt>
                                                        <dd className="mt-1 text-sm text-gray-900">
                                                            {
                                                                profile.fields[
                                                                    field
                                                                ]
                                                            }
                                                        </dd>
                                                    </div>
                                                ))}
                                                <div className="sm:col-span-2">
                                                    <dt className="text-sm font-medium text-gray-500">
                                                        About
                                                    </dt>
                                                    <dd
                                                        className="mt-1 max-w-prose space-y-5 text-sm text-gray-900"
                                                        dangerouslySetInnerHTML={{
                                                            __html: profile.about_me,
                                                        }}
                                                    />
                                                </div>
                                            </dl>
                                        </div>

                                        {/* Team member list */}
                                        <div className="mx-auto mt-8 max-w-5xl px-4 pb-12 sm:px-6 lg:px-8">
                                            <h2 className="text-sm font-medium text-gray-500">
                                                Previously worked with
                                            </h2>
                                            <div className="mt-1 grid grid-cols-1 gap-4 sm:grid-cols-2">
                                                {teamPlaceHolder.map(
                                                    (person) => (
                                                        <div
                                                            key={person.handle}
                                                            className="relative flex items-center space-x-3 rounded-lg border border-gray-300 bg-white px-6 py-5 shadow-sm focus-within:ring-2 focus-within:ring-blue-600 focus-within:ring-offset-2 hover:border-gray-400"
                                                        >
                                                            <div className="flex-shrink-0">
                                                                <img
                                                                    className="h-10 w-10 rounded-full"
                                                                    src={
                                                                        person.imageUrl
                                                                    }
                                                                    alt=""
                                                                />
                                                            </div>
                                                            <div className="min-w-0 flex-1">
                                                                <a
                                                                    href="#"
                                                                    className="focus:outline-none"
                                                                >
                                                                    <span
                                                                        className="absolute inset-0"
                                                                        aria-hidden="true"
                                                                    />
                                                                    <p className="text-sm font-medium text-gray-900">
                                                                        {
                                                                            person.name
                                                                        }
                                                                    </p>
                                                                    <p className="truncate text-sm text-gray-500">
                                                                        {
                                                                            person.role
                                                                        }
                                                                    </p>
                                                                </a>
                                                            </div>
                                                        </div>
                                                    )
                                                )}
                                            </div>
                                        </div>
                                    </>
                                )}
                            </article>
                        </main>
sqxo8psd

sqxo8psd1#

既然您确信消息已被传输,我认为问题在于此useEffect依赖性

useEffect(() => {           
    //Receive message from back-end
    socket.on('receive_message', (data) => {
        console.log(data);
        console.log(roomId);
        //If message is for this room
        if (data.room === roomId) {
            console.log(data);
            //Show message
            setMessages((list) => [...list, data]);
        }
    });
}, [roomId]);

这种依赖性意味着,useEffect内部的代码将在初始渲染时运行,之后只有当roomId改变时才运行。由于聊天期间roomId将是相同的原语值,因此useEffect将不运行。
我认为你也应该传递socket对象到第一个useEffect依赖项。这是一个对象。当你点击发送按钮时,sendMessage函数将运行。由于messages状态将被更新,组件将重新呈现,这将创建一个全新的socket对象。由于socket依赖项更改,将运行第一个useEffect,您将侦听receive_message事件。

相关问题