paint-brush
以下是构建实时聊天应用程序所需的框架经过@harishk22
947 讀數
947 讀數

以下是构建实时聊天应用程序所需的框架

经过 Harish13m2025/01/21
Read on Terminal Reader

太長; 讀書

在本教程中,我们将使用 Laravel、Nuxt 3、Sanctum 和 Laravel Reverb 构建实时聊天应用程序。我们将设置用户身份验证、连接到安全 API,并确保聊天即时更新,以获得流畅且响应迅速的体验。
featured image - 以下是构建实时聊天应用程序所需的框架
Harish HackerNoon profile picture
0-item

在本教程中,我们将使用 Laravel、Nuxt 3、Sanctum 和 Laravel Reverb 构建一个实时聊天应用程序,以处理用户之间的安全实时消息传递。我们将设置用户身份验证、连接到安全 API,并确保聊天即时更新,以获得流畅且响应迅速的体验。


我们将使用该模块来管理 SPA 身份验证,该模块可高效处理单页应用程序 (SPA) 和 API 身份验证。要了解有关使用此模块的更多信息,请参阅有关Nuxt 3 SPA 身份验证的文章。


在这个项目中,我们将配置 Laravel Reverb 进行实时事件广播,使用 Sanctum 实现身份验证,并构建一个动态显示和管理聊天消息的 Nuxt 3 前端。让我们开始吧!

先决条件

  • 对 Laravel、Sanctum 和 Nuxt 3 有基本熟悉。
  • 了解 Laravel 中的事件广播。
  • 使用 Sanctum 设置的 Laravel 项目。
  • Nuxt 3 已安装并配置为您的应用程序的前端。

步骤 1:设置 Laravel Sanctum 和 Laravel Reverb

首先,确保已安装并配置 Laravel Sanctum。Sanctum 允许对单页应用程序 (SPA) 进行基于令牌的身份验证。然后,安装并配置 Laravel Reverb 以实现实时功能。


将以下 Reverb 环境变量添加到您的.env文件中:

 REVERB_APP_ID=my-app-id REVERB_APP_KEY=my-app-key REVERB_APP_SECRET=my-app-secret REVERB_HOST="localhost" REVERB_PORT=8080 REVERB_SCHEME=http

步骤 2:创建聊天消息表迁移

要存储聊天消息,请为chat_messages表创建迁移。运行:

 php artisan make:migration create_chat_messages_table


更新迁移文件如下:

 Schema::create('chat_messages', function (Blueprint $table) { $table->id(); $table->foreignId('receiver_id'); $table->foreignId('sender_id'); $table->text('text'); $table->timestamps(); });


运行迁移来创建表:

 php artisan migrate

步骤 3:创建 MessageSent 事件

为了实时广播消息,请创建一个MessageSent事件类:

 php artisan make:event MessageSent


更新事件类:

 <?php namespace App\Events; use App\Models\ChatMessage; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Broadcasting\PrivateChannel; use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow; use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Queue\SerializesModels; class MessageSent implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public ChatMessage $message) { // } public function broadcastOn(): array { return [new PrivateChannel("chat.{$this->message->receiver_id}")]; } }

步骤 4:定义广播频道

channels.php中,定义广播频道:

 Broadcast::channel('chat.{id}', function ($user, $id) { return (int) $user->id === (int) $id; });

步骤 5:定义获取和发送消息的路由

添加这些路由来管理发送和检索聊天消息:

 Route::get('/messages/{user}', function (User $user, Request $request) { return ChatMessage::query() ->where(function ($query) use ($user, $request) { $query->where('sender_id', $request->user()->id) ->where('receiver_id', $user->id); }) ->orWhere(function ($query) use ($user, $request) { $query->where('sender_id', $user->id) ->where('receiver_id', $request->user()->id); }) ->with(['sender', 'receiver']) ->orderBy('id', 'asc') ->get(); })->middleware('auth:sanctum'); Route::post('/messages/{user}', function (User $user, Request $request) { $request->validate(['message' => 'required|string']); $message = ChatMessage::create([ 'sender_id' => $request->user()->id, 'receiver_id' => $user->id, 'text' => $request->message ]); broadcast(new MessageSent($message)); return $message; });

步骤 6:在 Nuxt 3 中配置 Reverb

为了允许 Nuxt 3 与 Reverb 连接,请将这些变量添加到.env文件中:

 NUXT_PUBLIC_REVERB_APP_ID=my-app-id NUXT_PUBLIC_REVERB_APP_KEY=my-app-key NUXT_PUBLIC_REVERB_APP_SECRET=my-app-secret NUXT_PUBLIC_REVERB_HOST="localhost" NUXT_PUBLIC_REVERB_PORT=8080 NUXT_PUBLIC_REVERB_SCHEME=http


然后,在nuxt.config.ts中加载它们:

 export default defineNuxtConfig({ runtimeConfig: { public: { REVERB_APP_ID: process.env.NUXT_PUBLIC_REVERB_APP_ID, REVERB_APP_KEY: process.env.NUXT_PUBLIC_REVERB_APP_KEY, REVERB_APP_SECRET: process.env.NUXT_PUBLIC_REVERB_APP_SECRET, REVERB_HOST: process.env.NUXT_PUBLIC_REVERB_HOST, REVERB_PORT: process.env.NUXT_PUBLIC_REVERB_PORT, REVERB_SCHEME: process.env.NUXT_PUBLIC_REVERB_SCHEME, }, }, });

步骤 7:在 Nuxt 3 中设置 Laravel Echo 客户端

要管理实时更新,请创建一个laravel-echo.client.ts插件:

 import Echo from "laravel-echo"; import Pusher, { type ChannelAuthorizationCallback } from "pusher-js"; declare global { interface Window { Echo: Echo; Pusher: typeof Pusher; } } export default defineNuxtPlugin(() => { window.Pusher = Pusher; const config = useRuntimeConfig(); const echo = new Echo({ broadcaster: "reverb", key: config.public.REVERB_APP_KEY, wsHost: config.public.REVERB_HOST, wsPort: config.public.REVERB_PORT ?? 80, wssPort: config.public.REVERB_PORT ?? 443, forceTLS: (config.public.REVERB_SCHEME ?? "https") === "https", enabledTransports: ["ws", "wss"], authorizer: (channel, options) => ({ authorize: (socketId, callback) => { useSanctumFetch("api/broadcasting/auth", { method: "post", body: { socket_id: socketId, channel_name: channel.name }, }) .then(response => callback(null, response)) .catch(error => callback(error, null)); }, }), }); return { provide: { echo } }; });

步骤8:在Nuxt 3中构建实时聊天界面

为了在我们的 Nuxt 3 应用中启用实时聊天功能,我创建了一个新页面, chats > [id].vue ,用户可以在其中选择其他用户并与他们聊天。此页面连接到 Laravel 后端以管理聊天消息和用户数据,并使用 Laravel Echo 和 WebSockets 进行实时更新和输入指示器。


以下是我们如何构建此聊天功能的详细说明:

步骤 8.1:加载选定用户的聊天数据

首先,我们使用useRoute可组合项从 URL 中检索userID 。此userID可识别我们正在聊天的用户,并加载必要的用户和聊天消息。

 const route = useRoute(); const userID = route.params.id; const { user: currentUser } = useSanctum<User>(); const { data: user } = await useAsyncData( `user-${userID}`, () => useSanctumFetch<User>(`/api/users/${userID}`) ); const { data: messages } = useAsyncData( `messages-${userID}`, () => useSanctumFetch<ChatMessage[]>(`/api/messages/${userID}`), { default: (): ChatMessage[] => [] } );

此代码片段使用自定义可组合useSanctumFetch在页面挂载时异步加载消息。

步骤 8.2:显示聊天消息

我们动态地呈现每条消息,并根据它们来自当前用户还是聊天参与者来设置它们的样式。

 <div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div>

聊天窗口使用nextTick()自动滚动到最新消息。

 watch( messages, () => { nextTick(() => messageContainerScrollToBottom()); }, { deep: true } ); function messageContainerScrollToBottom() { if (!messagesContainer.value) return; messagesContainer.value.scrollTo({ top: messagesContainer.value.scrollHeight, behavior: 'smooth' }); }

步骤 8.3:发送新消息

用户可以使用输入字段发送消息。提交后,会向 Laravel 后端发送 POST 请求。

 const newMessage = ref(""); const sendMessage = async () => { if (!newMessage.value.trim()) return; const messageResponse = await useSanctumFetch<ChatMessage>(`/api/messages/${userID}`, { method: "post", body: { message: newMessage.value } }); messages.value.push(messageResponse); newMessage.value = ""; };

消息发送后立即更新。

步骤 8.4:使用 Laravel Echo 实现实时功能

Laravel Echo 监听诸如MessageSenttyping类的关键事件。

 onMounted(() => { if (currentUser.value) { $echo.private(`chat.${currentUser.value.id}`) .listen('MessageSent', (response: { message: ChatMessage }) => { messages.value.push(response.message); }) .listenForWhisper("typing", (response: { userID: number }) => { isUserTyping.value = response.userID === user.value?.id; if (isUserTypingTimer.value) clearTimeout(isUserTypingTimer.value); isUserTypingTimer.value = setTimeout(() => { isUserTyping.value = false; }, 1000); }); } });

它处理实时消息更新和输入指示器,这些指示器在一秒钟不活动后消失。

步骤 8.5:打字指示器

为了显示打字指示器,我们用whisper触发“打字”事件。

 const sendTypingEvent = () => { if (!user.value || !currentUser.value) return; $echo.private(`chat.${user.value.id}`).whisper("typing", { userID: currentUser.value.id }); };

每当用户键入时就会发送此事件,并且收件人会看到键入指示。

步骤 8.6:用户界面

聊天界面包括一个带有选定用户姓名的标题以及消息部分和输入字段。

 <template> <div> <header v-if="user" class="bg-white shadow"> <div class="px-4 py-6 mx-auto max-w-7xl sm:px-6 lg:px-8"> <h1 class="text-2xl font-bold ">{{ user.name }}</h1> </div> </header> <div class="flex flex-col items-center py-5"> <div class="container w-full h-full p-8 space-y-3 bg-white rounded-xl"> <div v-if="currentUser"> <div class="flex flex-col justify-end h-80"> <div ref="messagesContainer" class="p-4 overflow-y-auto max-h-fit"> <div v-for="message in messages" :key="message.id" class="flex items-center mb-2"> <div v-if="message.sender_id === currentUser.id" class="p-2 ml-auto text-white bg-blue-500 rounded-lg"> {{ message.text }} </div> <div v-else class="p-2 mr-auto bg-gray-200 rounded-lg"> {{ message.text }} </div> </div> </div> </div> <div class="flex-shrink-0"> <span v-if="user && isUserTyping" class="text-gray-500"> {{ user.name }} is typing... </span> <div class="flex items-center justify-between w-full p-4 border-t border-gray-200"> <input type="text" v-model="newMessage" @keydown="sendTypingEvent" @keyup.enter="sendMessage" class="w-full p-2 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Type a message..." /> <button @click.prevent="sendMessage" class="inline-flex items-center justify-center w-12 h-12 ml-4 text-white bg-blue-500 rounded-lg hover:bg-blue-600"> <svg xmlns="http://www.w3.org/2000/svg" class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" /> </svg> </button> </div> </div> </div> </div> </div> </div> </template>

这完成了使用 Laravel Sanctum 和 Echo 与 Nuxt 3 的实时聊天功能设置。

结论

我们现在使用 Laravel、Sanctum、Reverb 和 Nuxt 3 创建了一个安全的实时聊天应用程序。此设置可以轻松扩展以包含消息反应或多个聊天室等附加功能。


如需完整代码,请访问GitHub 存储库