在本教程中,我们将介绍如何构建一个简单而有效的实时聊天应用程序。该应用程序使用 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 举报,一经查实,本站将立刻删除。