前言
實踐是檢驗真理的唯一標准
正文
如何將Gin框架的后端與WebSocket服務寫在一起, 以達到共用一個端口的情況呢?
我們來看單純使用 net 包和 WS 結合
package main
import (
"flag"
"fmt"
"log"
"net/http"
"github.com/gorilla/websocket"
)
var addr = flag.String("addr", "localhost:8080", "http service address")
var upgrader = websocket.Upgrader{
// 解決跨域問題
CheckOrigin: func(r *http.Request) bool {
return true
},
} // use default options
func ws(w http.ResponseWriter, r *http.Request) {
c, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer c.Close()
for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = c.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
func main() {
flag.Parse()
log.SetFlags(0)
http.HandleFunc("/ws", ws)
fmt.Println(*addr)
log.Fatal(http.ListenAndServe(*addr, nil))
}
其實本質來說, WS服務在握手的過程中最開始也是HTTP請求, 然后再 Upgrade 到WS模式的, Upgrade函數接受三個參數, 一個是返回值套接字, 一個是請求套接字, 一個是返回值的頭, 而對於 Gin 的上下文 gin.Context 來說也是有這些數據的, 因此我們修改成
package control
import (
"log"
"net/http"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
// 解決跨域問題
CheckOrigin: func(r *http.Request) bool {
return true
},
} // use default options
func cmdWebSocket(c *gin.Context) {
ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Print("upgrade:", err)
return
}
defer ws.Close()
for {
mt, message, err := ws.ReadMessage()
if err != nil {
log.Println("read:", err)
break
}
log.Printf("recv: %s", message)
err = ws.WriteMessage(mt, message)
if err != nil {
log.Println("write:", err)
break
}
}
}
即可