Skip to main content

如何与 Nuxt 一起使用

¥How to use with Nuxt

本指南展示了如何在 Nuxt 应用中使用 Socket.IO。

¥This guide shows how to use Socket.IO within a Nuxt application.

服务器

¥Server

在底层,Nuxt 使用 硝基 来处理 HTTP 请求。

¥Under the hood, Nuxt uses Nitro to handle the HTTP requests.

将 Socket.IO 服务器连接到 Nitro 服务器有两个步骤:

¥There are two steps to attach a Socket.IO server to a Nitro server:

启用 WebSocket

¥Enable WebSockets

Nitro 中的 WebSockets 支持目前为 experimental,因此需要手动启用:

¥WebSockets support in Nitro is currently experimental, so it needs to be manually enabled:

nuxt.config.js
// https://nuxt.nodejs.cn/docs/api/configuration/nuxt-config

export default defineNuxtConfig({
devtools: {
enabled: true
},
+ nitro: {
+ experimental: {
+ websocket: true
+ },
+ }
})

参考:https://nitro.unjs.io/guide/websocket

¥Reference: https://nitro.unjs.io/guide/websocket

钩子 Socket.IO 服务器

¥Hook the Socket.IO server

我们的 Socket.IO 服务器是在 硝基插件 中创建的:

¥Our Socket.IO server is created in a Nitro plugin:

server/plugins/socket.io.ts
import type { NitroApp } from "nitropack";
import { Server as Engine } from "engine.io";
import { Server } from "socket.io";
import { defineEventHandler } from "h3";

export default defineNitroPlugin((nitroApp: NitroApp) => {
const engine = new Engine();
const io = new Server();

io.bind(engine);

io.on("connection", (socket) => {
// ...
});

nitroApp.router.use("/socket.io/", defineEventHandler({
handler(event) {
engine.handleRequest(event.node.req, event.node.res);
event._handled = true;
},
websocket: {
open(peer) {
// @ts-expect-error private method and property
engine.prepare(peer._internal.nodeReq);
// @ts-expect-error private method and property
engine.onWebSocket(peer._internal.nodeReq, peer._internal.nodeReq.socket, peer.websocket);
}
}
}));
});

瞧!

¥And voilà!

客户端

¥Client

在客户端,我们 Vue 3 指南 的所有提示都是有效的。

¥On the client side, all tips from our Vue 3 guide are valid.

唯一的区别是你需要从服务器端渲染(SSR)中排除 Socket.IO 客户端:

¥The only difference is that you need to exclude the Socket.IO client from server-side rendering (SSR):

结构:

¥Structure:

├── components
│ ├── Connection.client.vue
│ └── socket.ts
...
components/socket.ts
import { io } from "socket.io-client";

export const socket = io();
components/Connection.client.vue
<script setup>
import { socket } from "./socket";

const isConnected = ref(false);
const transport = ref("N/A");

if (socket.connected) {
onConnect();
}

function onConnect() {
isConnected.value = true;
transport.value = socket.io.engine.transport.name;

socket.io.engine.on("upgrade", (rawTransport) => {
transport.value = rawTransport.name;
});
}

function onDisconnect() {
isConnected.value = false;
transport.value = "N/A";
}

socket.on("connect", onConnect);
socket.on("disconnect", onDisconnect);

onBeforeUnmount(() => {
socket.off("connect", onConnect);
socket.off("disconnect", onDisconnect);
});

</script>

<template>
<div>
<p>Status: {{ isConnected ? "connected" : "disconnected" }}</p>
<p>Transport: {{ transport }}</p>
</div>
</template>

note

Connection.client.vue 中的 .client 后缀表示该组件仅在客户端渲染(无 SSR)。

¥The .client suffix in Connection.client.vue indicates that the component is meant to be rendered only client-side (no SSR).

参考:https://nuxt.nodejs.cn/docs/guide/directory-structure/components#client-components

¥Reference: https://nuxt.nodejs.cn/docs/guide/directory-structure/components#client-components

在上面的示例中,transport 变量是用于建立 Socket.IO 连接的底层传输,它可以是:

¥In the example above, the transport variable is the low-level transport used to establish the Socket.IO connection, which can be either:

  • HTTP 长轮询 ("polling")

    ¥HTTP long-polling ("polling")

  • WebSocket("websocket")

  • WebTransport("webtransport")

如果一切顺利,你应该看到:

¥If everything went well, you should see:

Status: connected
Transport: websocket

然后,你可以在 Socket.IO 服务器和客户端之间交换消息:

¥You can then exchange messages between the Socket.IO server and client with:

  • socket.emit() 发送消息

    ¥socket.emit() to send messages

socket.emit("hello", "world");
  • socket.on() 接收消息

    ¥socket.on() to receive messages

socket.on("hello", (value) => {
// ...
});

以上就是全部内容了,感谢大家的阅读!

¥That's all folks, thanks for reading!

返回示例列表

¥Back to the list of examples