首頁 > web前端 > js教程 > 使用 Socket.io 和 Redis 建置和部署聊天應用程式。

使用 Socket.io 和 Redis 建置和部署聊天應用程式。

王林
發布: 2024-08-26 21:40:32
原創
560 人瀏覽過

Build and deploy a chat application using Socket.io and Redis.

在本教學中,我們將使用 Web 套接字建立一個聊天應用程式。當您想要建立需要即時傳輸資料的應用程式時,Web 套接字非常有用。

在本教程結束時,您將能夠設定自己的套接字伺服器、即時發送和接收訊息、在 Redis 中儲存資料以及在渲染和 google cloud run 上部署應用程式。

我們將建造什麼?

我們將建立一個聊天應用程式。為了簡單起見,我們將只設定伺服器。您可以使用自己的前端框架並遵循。

在這個聊天應用程式中,會有房間,使用者可以加入房間並開始聊天。為了讓一切簡單,我們假設使用者名稱不是唯一的。然而,每個房間只能有一個具有特定使用者名稱的使用者。

設定套接字伺服器。

首先我們需要安裝所需的依賴項。

npm i express cors socket.io -D @types/node
登入後複製

我們將使用 http 模組來設定我們的套接字伺服器。由於我們的應用程式將在終端中運行,因此我們必須允許所有來源。

import express from "express";
import cors from "cors"
import { Server } from "socket.io";
import { createServer } from "http"

const app = express();
const server = createServer(app);

// create a socket server.
const io = new Server(server, {
  cors: {
    origin: "*",
    credentials: true,
  }
});

// listen to connections errors
io.engine.on("connection_error", console.log)

app.use(cors())

const PORT = 3000;
server.listen(PORT, () => console.log(`Server running on port ${PORT}`));
登入後複製

設定 Redis。

我們將使用 Redis 來儲存我們的訊息以及房間和使用者資訊。您可以使用 upstash redis (免費)。在 upstash 儀表板中建立一個新的 Redis 實例。建立後,您將收到一個 redis url,您可以使用它來連接到您的 redis 實例。

安裝您選擇的任何 Redis 用戶端。我將使用 ioredis。

npm i ioredis
登入後複製

接下來,我們將初始化我們的 Redis 用戶端,並使用我們獲得的連接 url 將其連接到我們的 Redis 伺服器。

/** /src/index.ts */
import { Redis } from "ioredis"

if (!process.env.REDIS_URL) throw new Error("REDIS_URL env variable is not set");
const redis = new Redis(process.env.REDIS_URL);

// listen to connection events.
redis.on("connect", () => console.log("Redis connected"))
redis.on("error", console.log)
登入後複製

處理事件。

使用者可以建立房間或加入現有房間。房間由唯一的房間 ID 標識。每個成員都有一個用戶名,該用戶名在房間內是唯一的,而不是全域的。

我們可以透過將房間 ID 儲存在 Redis 集中來追蹤伺服器中的所有活動房間。

就我們的目的而言,使用者名稱僅在房間內是唯一的。因此,我們將它們與房間 ID 一起儲存在一個集合中。這可確保房間 ID 與會員 ID 的組合在全球範圍內是唯一的。

我們可以設定套接字事件來建立房間。當我們建立房間時,我們也將請求建立房間的成員加入房間。

io.on("connection", () => {
    // ...
    socket.on("create:room", async (message) => {
        console.log("create:room", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 1) return socket.emit("error", { message: "Room already exist."})

        const roomStatus = await redis.sadd("rooms", message.roomId)
        const memStatus = await redis.sadd("members", message.roomId + "::" + message.username)

        if (roomStatus === 0 || memStatus === 0) return socket.emit("error", { message: "Room creation failed." })

        socket.join(message.roomId)
        io.sockets.in(message.roomId).emit("create:room:success", message)
        io.sockets.in(message.roomId).emit("add:member:success", message)
  })
}
登入後複製

要將新成員加入現有房間中,我們首先需要檢查該成員是否已存在於該房間中。

io.on("connection", () => {
    // ...
    socket.on("add:member", async (message) => {
        console.log("add:member", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." })

        const doesMemExist = await redis.sismember("members", message.roomId + "::" + message.username)
        if (doesMemExist === 1) return socket.emit("error", { message: "Username already exists, please choose another username." })

        const memStatus = await redis.sadd("members", message.roomId + "::" + message.username)
        if (memStatus === 0) return socket.emit("error", { message: "User creation failed." })

        socket.join(message.roomId)
        io.sockets.in(message.roomId).emit("add:member:success", message)
  })

    socket.on("remove:member", async (message) => {
        console.log("remove:member", message)

        const doesRoomExist = await redis.sismember("rooms", message.roomId)
        if (doesRoomExist === 0) return socket.emit("error", { message: "Room does not exist." })

        await redis.srem("members", message.roomId + "::" + message.username)

        socket.leave(message.roomId)
        io.sockets.in(message.roomId).emit("remove:member:success", message)
      })
}
登入後複製

最後,我們建立聊天事件。

io.on("connection", () => {
    socket.on("create:chat", (message) => {
    console.log("create:chat", message)
    redis.lpush("chat::" + message.roomId, message.username + "::" + message.message)
    io.sockets.in(message.roomId).emit("create:chat:success", message)
  })
}
登入後複製

部署。

Socket 伺服器需要持久連接,它在無伺服器環境中無法運作。所以你不能在 vercel 中部署你的套接字伺服器。

您可以將其部署在許多地方,例如 Render、fly.io 或 Google Cloud Run。

使成為

在渲染上部署很簡單。如果您有 dockerfile,它將自動從該 dockerfile 建置您的專案。渲染有一個免費圖層,但請記住免費圖層中會有冷啟動。

這是我的 dockerfile。

# syntax=docker/dockerfile:1
ARG NODE_VERSION=20.13.1
ARG PNPM_VERSION=9.4.0

FROM node:${NODE_VERSION}-bookworm AS base

## set shell to bash
SHELL [ "/usr/bin/bash", "-c" ]
WORKDIR /usr/src/app

## install pnpm.
RUN --mount=type=cache,target=/root/.npm \
    npm install -g pnpm@${PNPM_VERSION}

# ------------
FROM base AS deps
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.local/share/pnpm/store to speed up subsequent builds.
# Leverage bind mounts to package.json and pnpm-lock.yaml to avoid having to copy them
# into this layer.
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
    --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --prod --frozen-lockfile

# -----------
FROM deps AS build
## downloading dev dependencies.
RUN --mount=type=bind,source=package.json,target=package.json \
    --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
    --mount=type=cache,target=/root/.local/share/pnpm/store \
    pnpm install --frozen-lockfile

COPY . .
RUN pnpm run build

# -------------
FROM base AS final
ENV NODE_ENV=production
USER node
COPY package.json .

# Copy the production dependencies from the deps stage and also
# the built application from the build stage into the image.
COPY --from=deps /usr/src/app/node_modules ./node_modules
COPY --from=build /usr/src/app/dist ./dist

EXPOSE 3000
ENTRYPOINT [ "pnpm" ]
CMD ["run", "start"]
登入後複製

谷歌雲端運行

如果您想要一個免費的渲染替代方案並避免冷啟動,您應該使用 Google Cloud Run。在雲端運行上部署的步驟超出了本文的範圍,但這裡是您需要執行的操作的簡短清單。

  1. 從下面提供的 dockerfile 建置 docker 映像。

  2. 使用 Google Artifact Registry 服務建立工件儲存庫。

  3. 將 docker 映像重新命名為格式 -docker.pkg.dev//:

  4. 將您的映像推送到您的工件儲存庫。

  5. 將映像部署到 Google Cloud Run。確保將最小活動實例設為 1,以避免冷啟動。

本教學就是這樣。

感謝您的閱讀❣️

以上是使用 Socket.io 和 Redis 建置和部署聊天應用程式。的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:dev.to
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板