使用 Redis Pub/Sub、Golang 和 WebSocket 构建实时聊天应用程序

实时应用程序已成为现代网络开发的基石,可实现即时通信和交互。在本教程中,我们将使用 Golang、Redis Pub/Sub 和 WebSocket 构建一个实时聊天应用程序。在本指南结束时,您将拥有一个支持多用户和实时消息广播的功能齐全的聊天应用程序。

前提条件

在深入学习之前,请确保已安装以下设备:

  • Redis:从 redis.io/download 下载并安装。
  • Golang:从 golang.org/dl 下载并安装。

项目结构

项目结构如下:

chat-app/
├── main.go
└── web/
 ├── index.html
 └── main.js

步骤 1:使用 Golang 设置后台

首先,为项目创建一个目录并初始化 Go 模块:

mkdir chat-app
cd chat-app
go mod init chat-app

安装必要的 Go 软件包:

go get github.com/go-redis/redis/v8
go get github.com/gorilla/mux
go get github.com/gorilla/websocket

接下来,创建包含以下内容的main.go文件:

package main

import (
 "context"
 "log"
 "net/http"

 "github.com/go-redis/redis/v8"
 "github.com/gorilla/mux"
 "github.com/gorilla/websocket"
)

var (
 ctx = context.Background()
 rdb = redis.NewClient(&redis.Options{
  Addr: "localhost:6379",
 })
 upgrader = websocket.Upgrader{
  CheckOrigin: func(r *http.Request) bool {
   return true
  },
 }
)

func main() {
 r := mux.NewRouter()
 r.HandleFunc("/ws/{channel}", handleWebSocket)

 fs := http.FileServer(http.Dir("./web"))
 r.PathPrefix("/").Handler(fs)

 log.Println("Server started on :8080")
 log.Fatal(http.ListenAndServe(":8080", r))
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
 vars := mux.Vars(r)
 channel := vars["channel"]

 conn, err := upgrader.Upgrade(w, r, nil)
 if err != nil {
  log.Println(err)
  return
 }
 defer conn.Close()

 sub := rdb.Subscribe(ctx, channel)
 defer sub.Close()
 ch := sub.Channel()

 go func() {
  for {
   _, msg, err := conn.ReadMessage()
   if err != nil {
    log.Println("Read error:", err)
    return
   }

   if err := rdb.Publish(ctx, channel, string(msg)).Err(); err != nil {
    log.Println("Publish error:", err)
    return
   }
  }
 }()

 for msg := range ch {
  if err := conn.WriteMessage(websocket.TextMessage, []byte(msg.Payload)); err != nil {
   log.Println("Write error:", err)
   return
  }
 }
}

步骤 2:创建前

创建一个Web目录,并添加 index.html 和 main.js 文件。

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Real-Time Chat</title>
    <style>
        body {
            font-family: Arial, sans-serif;
        }
        #messages {
            height: 300px;
            border: 1px solid #ccc;
            overflow-y: scroll;
            padding: 10px;
        }
        #form {
            margin-top: 10px;
        }
    </style>
</head>
<body>
    <h1>Real-Time Chat</h1>
    <div id="usernameInput">
        <label for="username">Enter Your Username:</label>
        <input type="text" id="username" placeholder="Username" autocomplete="off">
        <button onclick="submitUsername()">Submit</button>
    </div>
    <div id="chat" style="display:none;">
        <div id="messages"></div>
        <form id="form">
            <input type="text" id="input" placeholder="Type a message..." autocomplete="off">
            <button>Send</button>
        </form>
    </div>
    <script src="main.js"></script>
</body>
</html>

main.js

let username = '';

function submitUsername(event) {
    if (event) event.preventDefault();
    username = document.getElementById('username').value.trim();
    if (username) {
        document.getElementById('usernameInput').style.display = 'none';
        document.getElementById('chat').style.display = 'block';
        startWebSocket();
    } else {
        alert('Please enter a valid username.');
    }
}

function startWebSocket() {
    const messages = document.getElementById('messages');
    const form = document.getElementById('form');
    const input = document.getElementById('input');

    const ws = new WebSocket('ws://localhost:8080/ws/general');

    ws.onmessage = (event) => {
        const message = document.createElement('div');
        message.textContent = event.data;
        messages.appendChild(message);
    };

    form.addEventListener('submit', (event) => {
        event.preventDefault();
        const message = input.value.trim();
        if (message) {
            ws.send(username + ': ' + message);
            input.value = '';
        }
    });
}

// Add event listener for Enter key in the username input field
const usernameInput = document.getElementById('username');
usernameInput.addEventListener('keydown', (event) => {
    if (event.key === 'Enter') {
        submitUsername(event);
    }
});

运行应用程序

启动 Redis

打开终端窗口,运行以下命令启动 Redis 服务器:

redis-server

运行 Golang 服务器

打开一个新的终端窗口或标签页,导航到项目目录,然后运行:

go run main.go

该命令会在 localhost:8080 上启动 HTTP 服务器。

访问聊天界面

打开Web浏览器,导航至 http://localhost:8080。输入用户名并按 Enter 键或单击 “提交 “按钮加入聊天。

模拟聊天互动

模拟多个用户之间的交互:

打开 http://localhost:8080。输入用户名,以用户 1 的身份加入聊天。打开另一个浏览器窗口或标签页(最好是不同的浏览器或隐身/私人窗口),再次浏览 http://localhost:8080。输入不同的用户名,以用户 2 的身份加入聊天。

现在可以同时从两个用户处发送信息,并看到它们实时显示。

使用 Redis Pub/Sub、Golang 和 WebSocket 构建实时聊天应用程序

结论

使用 Redis Pub/Sub、Golang 和 WebSocket 构建实时聊天应用程序是了解实时网络应用基础知识的好方法。本教程包括使用 Golang 设置后端、处理 WebSocket 连接以及集成 Redis Pub/Sub 用于消息广播。我们还构建了一个简单的前端来与聊天应用程序进行交互。

您可以使用更多功能(如多个聊天室、消息持久化或用户身份验证)来扩展此应用程序,以增强您的学习和应用程序功能。

如需完整源代码,请访问 https://github.com/senowijayanto/go-chat-app.

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/im/49430.html

(0)

相关推荐

发表回复

登录后才能评论