前端vue后端go-gin实现websocket

5,379 阅读3分钟

Vue写一个简易客户端

<template>
  <div class="view">
    <input type="text" v-model="msg"><button @click="send">发言</button>
    <div class="chat-title">聊天记录:</div>
    <div v-for="(item,index) in msgList" :key="index" class="chat-box">{{item}}</div>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        msg: '',
        ws: '',
        msgList: []
      }
    },
    methods: {
      send() {
        this.ws.send(this.msg)
        //this.ws.send(JSON.stringify({msg: this.msg}))
        this.msg = ''
      }
    },
    mounted() {
      this.ws = new WebSocket('ws://127.0.0.1:3000/ping')
      // 连接打开时触发
      this.ws.onopen = () => {  
        console.log("Connection open ...") 
      }
      // 接收到消息时触发  
      this.ws.onmessage = (evt) => { 
        console.log(evt) 
        this.msgList.push(evt.data)  
      } 
      this.ws.onclose = () => {
        console.log('Connection close !!!')
      }
    },
    // 关闭连接 
    beforeDestroy() {
      this.ws.close()
    }
  }
</script>

<style scoped>
.view{
  width: 600px;
  margin: 0 auto;
  background-color:aliceblue;
  height: 500px;
  text-align: center;
  padding-top: 80px;
}
.chat-title{
  text-align:left;
  margin-left:100px;
  margin-top:50px;
}
.chat-box{
  background-color: white;
  width: 400px;
  margin: 0 auto;
}
</style>
  • data中定义三变量:msg发送消息载体,msgList接收服务端消息,ws为websocket对象。
  • vue生命周期mounted中页面渲染完成,就new一个websocket对象赋给ws,监听了三个事件。onmessage中当服务端有数据推送过来就push到msgList中,留给页面处理。
  • vue生命周期beforeDestory中,假如页面组件销毁就关闭ws连接。
  • 按钮事件send中,将input输入框中的数据msg发送给后端,其中我注释掉的代码是以json字符串的方式传输。

Go 服务端代码

首先进入main函数,完成对gin路由的初始

package main

import "go-websocket/route"

func main() {
	route.Init()
}

再看路由代码

package route

import (
	"go-websocket/controller/ws"

	"github.com/gin-gonic/gin"
)

// Init 路由初始化
func Init() {
	router := gin.Default()
	router.GET("/ping", ws.Ping)
	router.Run(":3000")
}

当前端页面渲染完成,就会来连接后端,不出意外就会进入这边的处理器函数ws.Ping

package ws

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
)

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

// type data struct {
// 	Msg string `json:"msg"`
// }

// Ping webSocket请求Ping 返回pong
func Ping(c *gin.Context) {
	//升级get请求为webSocket协议
	ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		return
	}
	defer ws.Close()
	for {
		// 读取ws中的数据
		mt, message, err := ws.ReadMessage()
		if err != nil {
			// 客户端关闭连接时也会进入
			fmt.Println(err)
			break
		}
		// msg := &data{}
		// json.Unmarshal(message, msg)
		// fmt.Println(msg)
		fmt.Println(mt)
		fmt.Println(message)
		fmt.Println(string(message))

		// 如果客户端发送ping就返回pong,否则数据原封不动返还给客户端
		if string(message) == "ping" {
			message = []byte("pong")
		}
		// 写入ws数据 二进制返回
		err = ws.WriteMessage(mt, message)
		// 返回JSON字符串,借助gin的gin.H实现
		// v := gin.H{"message": msg}
		// err = ws.WriteJSON(v)
		if err != nil {
			break
		}
	}
}

代码中有详细的注释,就不一一介绍了,其中被我注释掉的代码是服务端以json字符串的方式接收和发送数据。打印接收到的数据是以十进制显示的utf-8编码。

其中int类型的mt我不清楚是什么意思,我就跟踪了下源码。

// The message types are defined in RFC 6455, section 11.8.
const (
	// TextMessage denotes a text data message. The text message payload is
	// interpreted as UTF-8 encoded text data.
	TextMessage = 1

	// BinaryMessage denotes a binary data message.
	BinaryMessage = 2

	// CloseMessage denotes a close control message. The optional message
	// payload contains a numeric code and text. Use the FormatCloseMessage
	// function to format a close message payload.
	CloseMessage = 8

	// PingMessage denotes a ping control message. The optional message payload
	// is UTF-8 encoded text.
	PingMessage = 9

	// PongMessage denotes a pong control message. The optional message payload
	// is UTF-8 encoded text.
	PongMessage = 10
)

git地址 前端demo 后端demo 还行的话支持一下。