使用 Go 和 Vue.js 构建实时聊天应用程序

在本教程中,我们将介绍如何构建一个简单而有效的实时聊天应用程序。该应用程序使用 Go 编程语言处理服务器端逻辑,使用 Vue.js 处理前端,使用 Gorilla WebSocket 库处理 WebSocket 连接,使用户能够进行无缝对话。

使用的技术

后台(Go):

Go(或 Golang)是一种编程语言,以简单、高效和支持并发而著称。后端服务器使用 Go 语言实现,是聊天应用程序的基础。服务器使用 Gorilla WebSocket 库处理 WebSocket 连接。handleConnections 和 handleMessages 函数分别管理 WebSocket 连接和消息广播。

Go 中的 WebSocket 实现:

在 Go 中使用 github.com/gorilla/websocket 软件包来处理 WebSocket 连接。upgrader 变量用于将 HTTP 请求升级为 WebSocket 连接。handleConnections 函数将初始 HTTP 请求升级为 WebSocket 连接、注册客户端以及读写消息。handleMessages 函数会持续向所有已连接的 WebSocket 客户端广播消息。

前端(Vue.js):

Vue.js 是一个用于构建用户界面的 JavaScript 框架。它用于为聊天应用程序创建反应式动态用户界面。Vue.js 可帮助管理客户端应用程序状态、处理用户交互以及根据传入的 WebSocket 消息更新用户界面。

支持技术和库:

  • Materialize CSS
  • EmojiOne
  • CryptoJS
  • jQuery

文件夹结构

在深入了解代码之前,快速浏览一下项目的文件夹结构:

1. public: 包含前台文件(HTML、CSS、JavaScript)。

app.js: 设置了 WebSocket 的 Vue.js 应用程序入口点。
index.html: 聊天应用程序的 HTML 结构。
style.css:应用程序的自定义样式: 应用程序的自定义样式。

2. src: 包含 Go 后台代码。

main.go: 实现 WebSocket 服务器并处理 HTTP 请求。

后台代码说明

1. 设置 Go 模块:

第一步是初始化 Go 模块。具体方法是在项目目录中创建 go.mod 文件。

go mod init <module-name>

<module-name> 替换为 Go 模块的名称。

2. 安装依赖项:

由于此代码使用 Gorilla WebSocket 库,因此需要安装此依赖项。

go get -u github.com/gorilla/websocket

3. 创建项目结构:

在项目文件夹中创建以下目录结构:


└── src
    └── main.go

4. 代码

这段代码是在 Go 语言中使用 WebSockets 实现的一个简单聊天服务器。让我分解一下主要组件并解释其流程:

a. 导入:

import (
    "log"
    "net/http"
    "github.com/gorilla/websocket"
)

代码导入了必要的软件包: “log “用于记录日志,”net/http “用于处理 HTTP 请求,”github.com/gorilla/websocket “用于实现 WebSocket 功能。

b. 全局变量:

var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan Message)

c. WebSocket Upgrader:

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool {
        return true
    },
}

Upgrader 是用于将 HTTP 连接升级为 WebSocket 连接的配置结构体。CheckOrigin 函数用于允许来自任何来源的连接。

d. 消息结构:

type Message struct {
    Email    string `json:"email"`
    Username string `json:"username"`
    Message  string `json:"message"`
}

e. 主功能:

func main() {
    fs := http.FileServer(http.Dir("../public"))
    http.Handle("/", fs)

    http.HandleFunc("/ws", handleConnections)

    go handleMessages()

    log.Println("http server started on :8000")
    err := http.ListenAndServe(":8000", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

f. 处理连接函数:

func handleConnections(w http.ResponseWriter, r *http.Request) {
    ws, err := upgrader.Upgrade(w, r, nil)
    // ... (error handling)
    defer ws.Close()

    clients[ws] = true

    for {
        var msg Message
        err := ws.ReadJSON(&msg)
        // ... (error handling)
        broadcast <- msg
    }
}

g. 处理消息函数:

func handleMessages() {
    for {
        msg := <-broadcast
        for client := range clients {
            err := client.WriteJSON(msg)
            // ... (error handling)
        }
    }
}

h. 完整的 main.go 文件:

package main

import (
 "log"
 "net/http"

 "github.com/gorilla/websocket"
)

var clients = make(map[*websocket.Conn]bool) // connected clients
var broadcast = make(chan Message)           // broadcast channel

// Configure the upgrader
var upgrader = websocket.Upgrader{
 CheckOrigin: func(r *http.Request) bool {
  return true
 },
}

// Define our message object
type Message struct {
 Email    string `json:"email"`
 Username string `json:"username"`
 Message  string `json:"message"`
}

func main() {
 // Create a simple file server
 fs := http.FileServer(http.Dir("../public"))
 http.Handle("/", fs)

 // Configure websocket route
 http.HandleFunc("/ws", handleConnections)

 // Start listening for incoming chat messages
 go handleMessages()

 // Start the server on localhost port 8000 and log any errors
 log.Println("http server started on :8000")
 err := http.ListenAndServe(":8000", nil)
 if err != nil {
  log.Fatal("ListenAndServe: ", err)
 }
}

func handleConnections(w http.ResponseWriter, r *http.Request) {
 // Upgrade initial GET request to a websocket
 ws, err := upgrader.Upgrade(w, r, nil)
 if err != nil {
  log.Fatal(err)
 }
 // Make sure we close the connection when the function returns
 defer ws.Close()

 // Register our new client
 clients[ws] = true

 for {
  var msg Message
  // Read in a new message as JSON and map it to a Message object
  err := ws.ReadJSON(&msg)
  if err != nil {
   log.Printf("error: %v", err)
   delete(clients, ws)
   break
  }
  // Send the newly received message to the broadcast channel
  broadcast <- msg
 }
}

func handleMessages() {
 for {
  // Grab the next message from the broadcast channel
  msg := <-broadcast
  // Send it out to every client that is currently connected
  for client := range clients {
   err := client.WriteJSON(msg)
   if err != nil {
    log.Printf("error: %v", err)
    client.Close()
    delete(clients, client)
   }
  }
 }
}

5. 运行服务器

打开终端并运行以下命令启动 Go 服务器:

cd src 
go run main.go

该命令将在 localhost:8000 上启动 HTTP 服务器。您可以通过 ws://localhost:8000/ws 访问 WebSocket 服务器。

6. 测试 WebSocket 服务器

您可以使用 WebSocket 客户端或基于浏览器的 WebSocket 客户端,也可以使用 wscat 或 websocat 等专用工具。例如,使用 wscat:

# Install wscat
npm install -g wscat

# Connect to the WebSocket server
wscat -c ws://localhost:8000/ws

现在,您可以通过发送和接收信息与 WebSocket 服务器进行交互。

前台代码说明

聊天应用程序前端的 Vue.js 组件。Vue.js 组件位于 public/app.js 文件夹中,让我们一步步分解它:

new Vue({
    el: '#app',  // Mounting point for the Vue instance

    data: {
        ws: null,          // WebSocket connection
        newMsg: '',        // Holds new messages to be sent to the server
        chatContent: '',   // A running list of chat messages displayed on the screen
        email: null,       // Email address used for grabbing an avatar
        username: null,    // Our username
        joined: false      // True if email and username have been filled in
    },

    created: function() {
        var self = this;

        // WebSocket connection setup
        this.ws = new WebSocket('ws://' + window.location.host + '/ws');

        // Event listener for incoming WebSocket messages
        this.ws.addEventListener('message', function(e) {
            var msg = JSON.parse(e.data);

            // Update chat content with the received message
            self.chatContent += '<div class="chip">'
                + '<img src="' + self.gravatarURL(msg.email) + '">' // Avatar
                + msg.username
                + '</div>'
                + emojione.toImage(msg.message) + '<br/>'; // Parse emojis

            // Auto scroll to the bottom of the chat messages
            var element = document.getElementById('chat-messages');
            element.scrollTop = element.scrollHeight;
        });
    },

    methods: {
        // Method to send a new message to the server
        send: function() {
            if (this.newMsg != '') {
                this.ws.send(
                    JSON.stringify({
                        email: this.email,
                        username: this.username,
                        message: $('<p>').html(this.newMsg).text() // Strip out html
                    })
                );
                this.newMsg = ''; // Reset newMsg
            }
        },

        // Method to join the chat by entering email and username
        join: function() {
            if (!this.email) {
                Materialize.toast('You must enter an email', 2000);
                return;
            }
            if (!this.username) {
                Materialize.toast('You must choose a username', 2000);
                return;
            }
            this.email = $('<p>').html(this.email).text();
            this.username = $('<p>').html(this.username).text();
            this.joined = true;
        },

        // Method to generate a Gravatar URL based on email
        gravatarURL: function(email) {
            return 'http://www.gravatar.com/avatar/' + CryptoJS.MD5(email);
        }
    }
});

现在接下来是 html 文件,以下是文件夹public/index.html中聊天应用程序的 HTML 代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Simple Chat</title>

    <!-- External CSS Libraries -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/css/materialize.min.css">
    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/emojione/2.2.6/assets/css/emojione.min.css"/>
    <link rel="stylesheet" href="/style.css">
</head>
<body>
    <!-- Header -->
    <header>
        <nav>
            <div class="nav-wrapper">
                <a href="/" class="brand-logo right">Simple Chat</a>
            </div>
        </nav>
    </header>

    <!-- Main Section -->
    <main id="app">
        <!-- Chat Messages Section -->
        <div class="row">
            <div class="col s12">
                <div class="card horizontal">
                    <div id="chat-messages" class="card-content" v-html="chatContent">
                        <!-- Chat messages will be dynamically inserted here -->
                    </div>
                </div>
            </div>
        </div>

        <!-- Input Fields for Sending Messages -->
        <div class="row" v-if="joined">
            <div class="input-field col s8">
                <input type="text" v-model="newMsg" @keyup.enter="send">
            </div>
            <div class="input-field col s4">
                <button class="waves-effect waves-light btn" @click="send">
                    <i class="material-icons right">chat</i>
                    Send
                </button>
            </div>
        </div>

        <!-- Input Fields for Joining the Chat -->
        <div class="row" v-if="!joined">
            <div class="input-field col s8">
                <input type="email" v-model.trim="email" placeholder="Email">
            </div>
            <div class="input-field col s8">
                <input type="text" v-model.trim="username" placeholder="Username">
            </div>
            <div class="input-field col s4">
                <button class="waves-effect waves-light btn" @click="join()">
                    <i class="material-icons right">done</i>
                    Join
                </button>
            </div>
        </div>
    </main>

    <!-- Footer -->
    <footer class="page-footer">
        <!-- Footer content can be added here if needed -->
    </footer>

    <!-- External JavaScript Libraries -->
    <script src="https://unpkg.com/vue@2.1.3/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/emojione/2.2.6/lib/js/emojione.min.js"></script>
    <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/js/materialize.min.js"></script>
    
    <!-- Application-specific JavaScript -->
    <script src="/app.js"></script>
</body>
</html>

接下来是 CSS 代码,它负责设计聊天应用程序的布局样式,如下:

body {
    display: flex;
    min-height: 100vh;
    flex-direction: column;
}

main {
    flex: 1 0 auto;
}

#chat-messages {
    min-height: 10vh;
    height: 60vh;
    width: 100%;
    overflow-y: scroll;
}

整体效果:

  • 主体设置为具有列布局的弹性容器
  • 主要部分占据了弹性容器内剩余的垂直空间。
  • 主要部分中的#chat-messages div的样式具有固定高度,允许可滚动区域用于显示聊天消息。

结论

最后,本文使用 Vue.js 和 Go 构建了一个实时聊天应用程序。利用 WebSockets 的强大功能,用户可以无缝地参与对话。您可以根据自己的需求进一步探索和定制应用程序。

作者:Vinika Anthwal

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论