golang中关于websocket的使用的一些高级用法
很多网站都实现了“推送”功能,都会用到轮训这个技术,轮询就是每隔一段时间客户端就向服务器发送请求,来获得最新的数据。这种方式的缺点十分明显,浏览器每次发出的请求都含有比较大的header数据,浪费带宽资源。在这种背景下,HTML5定义了websocket协议,能够更好的节省服务器资源和带宽,而且可以实时的进行通信。
Golang官方推荐的一个包:github.com/gorilla/websocket
使用方法:go get github.com/gorilla/websocket
需求:通过websocket发来的数据在前端展示出来
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"github.com/gorilla/websocket"
)
type Message struct {
Name string `json:"name"`
Mess string `json:"mess"`
}
var clients = make(map[*websocket.Conn]bool)
var broadcast = make(chan *Message)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func rootHandler(w http.ResponseWriter, r *http.Request) {
content, err := ioutil.ReadFile("index.html")
if err != nil {
fmt.Println("could not find index.html")
}
fmt.Fprintf(w, "%s", content)
}
func writer(mess *Message) {
broadcast <- mess
}
func messHandler(w http.ResponseWriter, r *http.Request) {
var mess Message
if err := json.NewDecoder(r.Body).Decode(&mess); err != nil {
log.Printf("Error:%s", err)
http.Error(w, "Bad Request", http.StatusTeapot)
return
}
defer r.Body.Close()
go writer(&mess)
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Fatal(err)
}
clients[ws] = true
}
func echo() {
for {
mess := <-broadcast
hismess := fmt.Sprintf("%s : %s \n", mess.Name, mess.Mess)
fmt.Println(hismess)
for client := range clients {
err := client.WriteMessage(websocket.TextMessage, []byte(hismess))
if err != nil {
log.Printf("websocket error:%s", err)
client.Close()
delete(clients, client)
}
}
}
}
func main() {
http.HandleFunc("/", rootHandler)
http.HandleFunc("/chat", messHandler)
http.HandleFunc("/ws", wsHandler)
go echo()
panic(http.ListenAndServe(":7788", nil))
}
然后通过本地终端去发送请求,这里没有专门去写服务端代码
curl -H "Accept:application/json" -XPOST -d '{"name":"KOl","mess":"this is a test data"}' localhost:7788/chat
下面给出前端逻辑
<body>
<h1>Chat/History</h1>
<div id="mess"></div>
<script type="text/javascript">
var mess = document.getElementById("mess");
var exampleSocket = new WebSocket("ws://"+location.host+"/ws")
var update = function(){
exampleSocket.onmessage = function(event){
var chat = event.data;
var br = document.createElement("br");
mess.textContent = mess.textContent+chat.toString();
mess.appendChild(br);
}
};
window.setTimeout(update);
</script>
</body>
这个需求引入了channle,网络,map,goroutine相关的内容,可以好好品味。