iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 20
1
Modern Web

Go into Web!系列 第 20

Day20 | 製作一個公開匿名聊天室 - 後端篇

昨天將前端的部分寫好了,今天就讓我們將 Server 的部分處理好,建立一個公開的匿名聊天室吧!

今天的範例主要是要修改昨天所寫的 main.go,這邊我先將昨天的範例寫出來。

package main

import (
	"github.com/gin-gonic/gin"
	"net/http"
)

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("template/html/*")
	r.Static("/assets", "./template/assets")
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})
	r.Run(":5000")
}

Melody

本次的範例 WebSocket Server 的部分主要透過 melody 來處理。

簡介

melody 是基於由 gorilla 推出的 websocket package 所封裝,透過封裝好的簡易方法就可以體驗到 WebSocket 的強大功能。

安裝

使用 go get 的指令進行安裝。

go get gopkg.in/olahol/melody.v1

本次也會利用 gin 來實作 server,因此也需要進行安裝。

go get github.com/gin-gonic/gin

使用

建立 melody 物件

使用 melody 前首先要先建立好相關的物件。

m := melody.New()

設定 WebSocket Routing

接著我們使用 gin 來處理 routing,透過 melody 來處理連線的 request

r.GET("/ws", func(c *gin.Context) {
    m.HandleRequest(c.Writer, c.Request)
})

這樣就可以完成握手協定拉,是的,使用 melody 就是可以這麼簡單的完成 websocket 的連線!

設定連線與連線處理

因為連線與離線訊息我們都要透過傳送 message 的方式通知 client 端,因此我們要先設定訊息物件與相關方法

設定訊息物件與方法

訊息物件會有三個屬性

  • Event : 用來判斷訊息的類型
  • Name : 用來紀錄傳送的使用者 ID
  • Content : 訊息的內容
    這邊透過 NewMessage 方法建立 Message 物件
type Message struct {
	Event   string `json:"event"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewMessage(event, name, content string) *Message {
	return &Message{
		Event:   event,
		Name:    name,
		Content: content,
	}
}

由於透過 WebSocket 傳送訊息要使用 []byte 格式,因此這邊我們也將轉換的方法進行封裝

func (m *Message) GetByteMessage() []byte {
	result, _ := json.Marshal(m)
	return result
}

處理連線

melody 有提供 HandleConnect 方法讓我們處理連線的 session,我們這邊設定連線進來就發送一個 xxx 加入聊天室 的訊息給全部人

m.HandleConnect(func(session *melody.Session) {
    id := session.Request.URL.Query().Get("id")
    m.Broadcast(NewMessage("other", id, "加入聊天室").GetByteMessage())
})

處理離線

melody 有提供 HandleClose 方法讓我們處理離線的 session,我們這邊設定離線就發送一個 xxx 離開聊天室 的訊息給全部人

m.HandleClose(func(session *melody.Session, i int, s string) error {
    id := session.Request.URL.Query().Get("id")
    m.Broadcast(NewMessage("other", id, "離開聊天室").GetByteMessage())
    return nil
})

設定訊息接收與處理

完成連線與離線處理後,我們接著要處理由 client 傳送上來的 message,這邊也透過由 melody 提供的 HandleMessage 來處理傳入的訊息,因為我們是公開的聊天室,所以透過 Broadcast 將所有連線的 client 發送傳入的訊息。

m.HandleMessage(func(s *melody.Session, msg []byte) {
    m.Broadcast(msg)
})

匯總

目前 main.go 的整體程式如下

package main

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gopkg.in/olahol/melody.v1"
	"net/http"
)

type Message struct {
	Event   string `json:"event"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

func NewMessage(event, name, content string) *Message {
	return &Message{
		Event:   event,
		Name:    name,
		Content: content,
	}
}

func (m *Message) GetByteMessage() []byte {
	result, _ := json.Marshal(m)
	return result
}

func main() {
	r := gin.Default()
	r.LoadHTMLGlob("template/html/*")
	r.Static("/assets", "./template/assets")
	r.GET("/", func(c *gin.Context) {
		c.HTML(http.StatusOK, "index.html", nil)
	})

	m := melody.New()
	r.GET("/ws", func(c *gin.Context) {
		m.HandleRequest(c.Writer, c.Request)
	})

	m.HandleMessage(func(s *melody.Session, msg []byte) {
		m.Broadcast(msg)
	})

	m.HandleConnect(func(session *melody.Session) {
		id := session.Request.URL.Query().Get("id")
		m.Broadcast(NewMessage("other", id, "加入聊天室").GetByteMessage())
	})

	m.HandleClose(func(session *melody.Session, i int, s string) error {
		id := session.Request.URL.Query().Get("id")
		m.Broadcast(NewMessage("other", id, "離開聊天室").GetByteMessage())
		return nil
	})
	r.Run(":5000")
}

測試

連線測試

我們透過瀏覽器開啟兩個分頁,分別都連上 http://127.0.0.1:5000 這個網址,第二個分頁要可以看到

第一個分頁要可以看到

如果可以看到以上畫面就代表已經完成了連線測試!

訊息傳送測試

連線測試完成後,我們接著測試訊息傳送的功能,分別在分頁1與分頁2 輸入訊息 按下 Enter 後,應該可以看到以下畫面

切換至分頁2 應該可以看到以下畫面

這邊可以交互測試,就可以體驗到 WebSocket 即時通訊的強大之處了!

離線測試

最後我們來測試看看離線會有什麼效果,先將分頁2關閉,如果分頁1的畫面如下就代表離線測試通過拉!
[備註]一開始沒有存到圖,所以重開一次來測試QQ

小結

通過這兩天簡單的實作後,發現要做一個基本的聊天室不難,但是要了解 WebSocket 的機制已經整體的生命週期,希望這次的分享有幫助到大家,謝謝!

專案範例我放在這裡


上一篇
Day19 | 製作一個公開匿名聊天室 - 前端篇
下一篇
Day21 | 淺談 redis
系列文
Go into Web!30

尚未有邦友留言

立即登入留言