Gin + Gorilla Websocket
之前经过和添耀的交流,已经知道了在 go-gqlgel 的 subscription 怎么做了,不得不说资料确实有点匮乏,graphql 在国内的应用程度还是不高,不过 graphql 仍然是一门十分优秀的技术,我还是十分喜爱的。
不过这个博客是说 Gin 和 Gorilla怎么做 websocket 的,简单测试一下
安装
$ go get github.com/gorilla/websocket
$ go get -u github.com/gin-gonic/gin
使用
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"log"
"net/http"
)
var upgrade = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.GET("/ws", func(c *gin.Context) {
// 升级成 websocket 连接
ws, err := upgrade.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Fatalln(err)
}
// 完成时关闭连接释放资源
defer ws.Close()
go func() {
// 监听连接“完成”事件,其实也可以说丢失事件
<-c.Done()
// 这里也可以做用户在线/下线功能
fmt.Println("ws lost connection")
}()
for {
// 读取客户端发送过来的消息,如果没发就会一直阻塞住
mt, message, err := ws.ReadMessage()
if err != nil {
fmt.Println("read error")
fmt.Println(err)
break
}
if string(message) == "ping" {
message = []byte("pong")
}
err = ws.WriteMessage(mt, message)
if err != nil {
fmt.Println(err)
break
}
}
})
r.Run() // listen and serve on 0.0.0.0:8080
}
- 读取信息失败时,我们需要关注异常状态去解决异常,这里附带源码中的异常值
// Close codes defined in RFC 6455, section 11.7.
const (
CloseNormalClosure = 1000
CloseGoingAway = 1001
CloseProtocolError = 1002
CloseUnsupportedData = 1003
CloseNoStatusReceived = 1005
CloseAbnormalClosure = 1006
CloseInvalidFramePayloadData = 1007
ClosePolicyViolation = 1008
CloseMessageTooBig = 1009
CloseMandatoryExtension = 1010
CloseInternalServerErr = 1011
CloseServiceRestart = 1012
CloseTryAgainLater = 1013
CloseTLSHandshake = 1015
)
func (e *CloseError) Error() string {
s := []byte("websocket: close ")
s = strconv.AppendInt(s, int64(e.Code), 10)
switch e.Code {
case CloseNormalClosure:
s = append(s, " (normal)"...)
case CloseGoingAway:
s = append(s, " (going away)"...)
case CloseProtocolError:
s = append(s, " (protocol error)"...)
case CloseUnsupportedData:
s = append(s, " (unsupported data)"...)
case CloseNoStatusReceived:
s = append(s, " (no status)"...)
case CloseAbnormalClosure:
s = append(s, " (abnormal closure)"...)
case CloseInvalidFramePayloadData:
s = append(s, " (invalid payload data)"...)
case ClosePolicyViolation:
s = append(s, " (policy violation)"...)
case CloseMessageTooBig:
s = append(s, " (message too big)"...)
case CloseMandatoryExtension:
s = append(s, " (mandatory extension missing)"...)
case CloseInternalServerErr:
s = append(s, " (internal server error)"...)
case CloseTLSHandshake:
s = append(s, " (TLS handshake error)"...)
}
if e.Text != "" {
s = append(s, ": "...)
s = append(s, e.Text...)
}
return string(s)
}
测试
在 chrome 中安装插件:WebSocket King Client,这个名字非常霸气,确实也很好用,方便。
官网地址:websocketking.com/
测试成功,我们点击 Disconnection之后,服务端也监听到了连接的关闭。
总结
以上只是练习代码,实际生产环境中的要求和需求不会这么简单,所以一定会遇到像 http 请求那样的不同业务的 websocket 请求,这时就需要去做websocket中的路由分发了,这部分我们下章节再讲述。