Golang WebSocket Vue构建通信

文章目录

        • 1. 目标
        • 2. 项目目录
          • common\service_robot.go
          • server.go
          • myclient.go
          • WebSocket 客户端测试
          • Vue WebSocket 客户端
          • 前端的 WebSocket 测试

1. 目标

  1. 使用 Golang 编写一个WebSocker 服务端
    1. 能接受客户端的WebSocket连接
    2. 启动服务器时接收命令行参数
    3. 能响应客户端数据
      1. 模式一 : webSocket 回音模式
      2. 模式二 : 图灵机器人聊天模式
  2. 使用Golang 编写一个WebSocket 客户端
  3. 使用 Vue 编写一个WebSocket 客户端
    1. 能和服务端通信
    2. 能主动获取WebSocket当前状态
    3. 能主动关闭WebSocket连接
    4. 能主动重新连接WebSokct连接
    5. 能显示WebSocket通信数据

2. 项目目录

|__common
|____service_robot.go
| server.go
| myClient.go
common\service_robot.go

图灵机器人服务 , 提供给其他服务调用

package common

import (
	"bytes"
	"encoding/json"
	"errors"
	"io/ioutil"
	"log"
	"net/http"
)

var err error

const (
	// 你的图灵机器人 apikey
	APIKEY = ""
	// 你的 userId
	USERID = ""
	// 图灵的接口请求地址
	URL    = "http://openapi.tuling123.com/openapi/api/v2"
)

type ReqData struct {
	ReqType    int                    `json:"reqType"`
	Perception map[string]interface{} `json:"perception"`
	UserInfo   map[string]string      `json:"userInfo"`
}
type Result struct {
	ResultType string                 `json:"resultType"`
	Values     map[string]interface{} `json:"values"`
	GroupType  int                    `json:"groupType"`
}
type RespData struct {
	Intent  map[string]interface{} `json:"intent"`
	Results []Result               `json:"results"`
}

func NewRobot() *ReqData {
	info := map[string]string{
		"apiKey": APIKEY,
		"userId": USERID,
	}
	return &ReqData{
		ReqType:    0,
		Perception: nil,
		UserInfo:   info,
	}
}
func (r *ReqData) Chat(v interface{}) (error, []interface{}) {
	if val, ok := v.(string); ok {
		inputText := map[string]string{
			"text": val,
		}
		r.Perception = make(map[string]interface{})
		r.Perception["inputText"] = inputText
		jsonData, err := json.Marshal(r)
		if err == nil {
			return r.Post(jsonData)
		}
	} else {
		err = errors.New("format error")
	}
	return err, nil
}
func (r *ReqData) Post(data []byte) (error, []interface{}) {
	defer func() {
		if err != nil {
			log.Print("service_robot:post", err)
		}
	}()
	body := bytes.NewBuffer([]byte(data))
	req, err := http.NewRequest("POST", URL, body)
	if err == nil {
		req.Header.Add("Accept", "application/json")
		req.Header.Add("Content-Type", "application/json")
		resp, err := http.DefaultClient.Do(req)
		defer resp.Body.Close()
		if err != nil {
			return err, nil
		}
		result, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			return err, nil
		}
		log.Println(string(result))
		var response RespData
		err = json.Unmarshal(result, &response)
		if err != nil {
			return err, nil
		}
		var outPut []interface{}
		for _, v := range response.Results {
			for _, value := range v.Values {
				outPut = append(outPut, value)
			}
		}
		return nil, outPut
	}
	return err, nil
}

server.go

WebSocket 服务端

package main

import (
	"GoNote/chapter1/ws/common"
	"flag"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
)

var modeDescribe = `webSocket response model :
--echo default value
--robot The Turing robot responded
`
var addr = flag.String("addr", "", "http service addr")
var model = flag.String("model", "", modeDescribe)
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func echoFunc(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("upgrader :", err)
		return
	}
	defer func() {
		log.Println(c.RemoteAddr().String(), "connect close")
	}()
	defer c.Close()
	log.Println(c.RemoteAddr().String(), "connect success")
	var robot = common.NewRobot()
	for {
		mt, message, err := c.ReadMessage()
		if err != nil {
			break
		}
		//t := time.Now().Format("2006-01-02 15:04:05")
		m := string(message)
		log.Println("server receive message :", m)
		// robot 机器人应答
		if *model == "robot" {
			err, result := robot.Chat(m)
			if err == nil {
				for _, k := range result {
					if s, ok := k.(string); ok {
						message = []byte(s)
						err = c.WriteMessage(mt, message)
					}
				}
			}
		} else if *model == "echo" {
			// echo 回音服务
			message = []byte(m)
			err = c.WriteMessage(mt, message)
			if err != nil {
				log.Println("write :", err)
			}
		}
	}
}
func main() {
	flag.Parse()
	log.SetFlags(0)
	log.Println("addr : ", *addr)
	http.HandleFunc("/echo", echoFunc)
	log.Fatal(http.ListenAndServe(*addr, nil))
}

myclient.go

WebSocket 客户端

package main

import (
	"flag"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/url"
	"os"
	"os/signal"
)

var addr2 = flag.String("addr", "127.0.0.1:8080", "ws service addr")
var key string

func main() {
	defer func() {
		if err := recover(); err != nil {
			log.Println("error : ", err)
		}
	}()
	flag.Parse()
	log.SetFlags(0)
	interrupt := make(chan os.Signal, 1)
	signal.Notify(interrupt, os.Interrupt)
	u := url.URL{
		Scheme: "ws",
		Host:   *addr2,
		Path:   "/echo",
	}
	log.Printf("connecting to %s", u.String())
	c, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		log.Fatal("websocket connect error : ", err)
	}
	defer c.Close()
	receiveData := make(chan string)
	responseMessage := make(chan string)
	go func() {
		for {
			fmt.Print("请输入聊天内容 : ")
			fmt.Scan(&key)
			if key != "" {
				receiveData <- key
			}
			data := <-responseMessage
			fmt.Println("I receive message : ", data)
		}
	}()
	for {
		select {
		case <-interrupt:
			log.Println("interrupt")
			err := c.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
			if err != nil {
				log.Println("write close:", err)
				return
			}
			close(receiveData)
		case data := <-receiveData:
			err := c.WriteMessage(websocket.TextMessage, []byte(data))
			if err != nil {
				log.Println("write:", err)
				return
			}
			_, message, err := c.ReadMessage()
			if err != nil {
				log.Println("read from server err:", err)
			} else {
				responseMessage <- string(message)
			}
		}
	}
}
WebSocket 客户端测试
$ go run server.go -addr 127.0.0.1:8080 -model robot
addr :  127.0.0.1:8080
127.0.0.1:52402 connect success
server receive message : 北京天气
{"intent":{"actionName":"","code":10008,"intentName":"","parameters":{"date":"","city":"北京"}},"results":[{"groupType":1,"resultType":"text","values":{"text":"北京:周六 05月30日,雷阵雨 南风,最低气温18度,最高气温30度。"}}]}

$ go run myClient.go
connecting to ws://127.0.0.1:8080/echo
请输入聊天内容 : 北京天气
I receive message :  北京:周六 05月30日,雷阵雨 南风,最低气温18度,最高气温30度。
请输入聊天内容 :

Vue WebSocket 客户端

这边我们使用的 JavaScript 库是 Vue

也可以就用简单的html去实现


<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Documenttitle>
    
    <script src="https://unpkg.com/vue/dist/vue.js">script>
    
    <script src="https://unpkg.com/element-ui/lib/index.js">script>
    
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
head>

<body>
    <div id="app">
        <el-row :gutter="20">
            <el-col :span="16">
                <div class="grid-content bg-purple">
                    <el-input v-model="message" placeholder="请输入内容" @keyup.enter.native="submitMessage">el-input>
                div>
            el-col>
            <el-col :span="8">
                <div class="grid-content bg-purple">
                    <el-button @click="submitMessage">发送信息el-button>
                div>
            el-col>
        el-row>
        <el-row>
            <el-col :span="24">
                <div class="grid-content bg-purple-dark">
                    <el-button type="primary" @click="GetWsStatus">获取WS状态el-button>
                    <el-button type="success" @click="defaultWs">重新连接WSel-button>
                    <el-button type="info" @click="reloadPage">重新加载页面el-button>
                    <el-button type="warning" @click="showRespData" v-model="showButtonTitle">{{showButtonTitle}}数据el-button>
                    <el-button type="danger" @click="doCloseWS">关闭WS连接el-button>
                div>
            el-col>
        el-row>
        <el-row>
            <el-col :span="24">
                <div class="grid-content bg-purple-light" v-show="showSwitch && showData != ''" v-html="showData"> 
                div>
            el-col>
        el-row>
    div>
    <script>
        new Vue({
            el: '#app',
            data() {
                return {
                    addr: '127.0.0.1',
                    port: '8080',
                    message: '',
                    showSwitch: false,
                    showData: '',
                    showButtonTitle:'显示',
                    ws: null
                }
            },
            // 初始创建
            created() {
                this.defaultWs()
            },
            // 离开页面时销毁ws
            destroyed() {
                this.ws.close()
            },
            methods: {
                defaultWs() {
                    console.log('try to connect webSocket')
                    if ("WebSocket" in window) {
                        console.log('support webSocket')
                        var connectInfo = 'ws://' + this.addr + ':' + this.port + '/echo'
                        this.ws = new WebSocket(connectInfo)
                        this.ws.onopen = this.wsOnopen
                        this.ws.onmessage = this.wsOnMessage
                        this.ws.onclose = this.wsOnClose
                    }
                },
                wsOnopen() {
                    console.log('connect success')
                },
                wsOnMessage(e) {
                    console.log('receive data: ')
                    this.showData += ''+ e.data + ' : say server' + '
'
console.log(e.data) console.log(this.showData) }, wsOnClose(e) { this.ws.close() }, wsOnSend(data) { this.ws.send(data) }, // 提交信息 submitMessage() { if (this.message !== '') { console.log('submit some data....') this.wsOnSend(this.message) this.showData += 'I say:' + this.message+'
'
this.message = '' } }, // ws 状态查询 GetWsStatus() { switch (this.ws.readyState) { // 正在连接 case WebSocket.CONNECTING: this.$message({ message: 'WebSocket正在连接', }) break // 连接成功 case WebSocket.OPEN: this.$message({ message: 'WebSocket连接成功', type:'success' }) break // 已经关闭 case WebSocket.CLOSED: this.$message({ message: 'WebSocket连接已经关闭', type: 'error' }) break // 正在关闭 case WebSocket.CLOSING: this.$message({ message: 'WebSocket连接正在关闭', }) break } }, // 执行关闭ws doCloseWS() { this.wsOnClose() this.$message({ message: 'WebSocket关闭成功', type: 'success' }); }, // 重新加载页面 reloadPage() { location.reload() }, // 显示获取的数据 showRespData() { this.showSwitch ? this.showButtonTitle = '显示' : this.showButtonTitle='隐藏' this.showSwitch ? this.showSwitch = false : this.showSwitch = true } }, })
script> body> <style> .el-row { margin-top: 10px; } .bg-purple-light { background-color: aliceblue; } .speak-input { height: 200px; } style> html>
前端的 WebSocket 测试

Golang WebSocket Vue构建通信_第1张图片

你可能感兴趣的:(Golang)