-
1、接入鉴权
websocket
也可以和普通api
接口一样的做一个接口鉴权(token
机制),如果验证通过可以继续往下走,没有验证不能往下走
func Chat(ctx *gin.Context) {
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
}
-
2、实现鉴权处理
func Chat(ctx *gin.Context) {
userId := ctx.DefaultQuery("userId", "")
token := ctx.DefaultQuery("token", "")
userIdInt, _ := strconv.ParseInt(userId, 10, 64)
isValied := checkToken(userIdInt, token)
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return isValied
},
}
}
func checkToken(userId int64, token string) bool {
...
return true
}
-
3、将普通的get
请求升级为websocket
请求
...
conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil)
if err != nil {
fmt.Println("websocket连接错误")
return
}
-
4、conn
连接句柄的维护
type Node struct {
Conn *websocket.Conn
DataQueue chan []byte
GroupSet set.Interface
}
var clientMap map[int64]*Node = make(map[int64]*Node, 0)
var rwLocker sync.RWMutex
-
5、每次创建连接后将映射关系进行绑定
func Chat(ctx *gin.Context) {
userId := ctx.DefaultQuery("userId", "")
token := ctx.DefaultQuery("token", "")
userIdInt, _ := strconv.ParseInt(userId, 10, 64)
fmt.Println(token, userId, "=======")
isValied := checkToken(userIdInt, token)
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return isValied
},
}
conn, err := upGrader.Upgrade(ctx.Writer, ctx.Request, nil)
if err != nil {
fmt.Println("websocket连接错误")
return
}
node := &Node{
Conn: conn,
DataQueue: make(chan []byte, 50),
GroupSet: set.New(set.ThreadSafe),
}
rwLocker.Lock()
clientMap[userIdInt] = node
rwLocker.Unlock()
}
-
6、创建一个发送消息到管道中
func sendMsg(userId int64, message []byte) {
rwLocker.RLock()
node, isOk := clientMap[userId]
rwLocker.RUnlock()
if isOk {
node.DataQueue <- message
}
}
-
7、创建一个方法从管道中获取数据发送给前端
func senProc(node *Node) {
for {
select {
case data := <-node.DataQueue:
err := node.Conn.WriteMessage(websocket.TextMessage, data)
if err != nil {
fmt.Println("发送消息失败")
return
}
}
}
}
-
8、在Chat
方法中使用
func Chat(ctx *gin.Context) {
...
sendMsg(userIdInt, []byte("hello word"))
go senProc(node)
}
-
9、接收客户端消息转发给另外一个用户
func recvProc(node *Node) {
for {
_, data, err := node.Conn.ReadMessage()
if err != nil {
fmt.Println("接收数据失败", err)
return
}
dispatch(data)
}
}
func dispatch(data []byte) {
type Message struct {
UserId int64 `json:"userId"`
Msg string `json:"msg"`
}
fmt.Println("接收到的数据", string(data))
message := Message{}
err := json.Unmarshal(data, &message)
if err != nil {
fmt.Println("解析数据失败:", err.Error())
return
}
fmt.Println("解析的数据为:", message)
sendMsg(message.UserId, data)
}
-
10、使用接收客户端数据的方法
func Chat(ctx *gin.Context) {
...
sendMsg(userIdInt, []byte("hello word"))
go senProc(node)
go recvProc(node)
}
-
11、定义一个对外的方法(比如在别的接口中要发送数据到websocket
中)
func SendMessage(userId int64, message interface{}) {
str, _ := json.Marshal(message)
sendMsg(userId, str)
}