使用GOframe框架进行websocket开发相当简单。我们以下通过实现一个简单的echo服务器来演示GoFrame框架的websocket的使用(客户端使用HTML5实现)。示例代码:https://github.com/gogf/gf/v2/tree/master/.example/net/ghttp/server/websocket

先上H5客户端的代码
gf websocket echo server
注意我们这里的服务端连接地址为:ws://127.0.0.1:8199/ws。
客户端的功能很简单,主要实现了这几个功能:
websocket连接状态保持及信息展示; websocket服务端; websocket的返回信息后回显在界面上;package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/glog"
)
var ctx = gctx.New()
func main() {
s := g.Server()
s.BindHandler("/ws", func(r *ghttp.Request) {
ws, err := r.WebSocket()
if err != nil {
glog.Error(ctx,err)
r.Exit()
}
for {
msgType, msg, err := ws.ReadMessage()
if err != nil {
return
}
if err = ws.WriteMessage(msgType, msg); err != nil {
return
}
}
})
s.SetServerRoot(gfile.MainPkgPath())
s.SetPort(8199)
s.Run()
}
可以看到,服务端的代码相当简单,这里需要着重说明的是2个地方:
WebSocket方法: websocket服务端的路由注册方式和普通的http回调函数注册方式一样,但是在接口处理中我们需要通过ghttp.Request.WebSocket方法(这里直接使用指针对象r.WebSocket())将请求转换为websocket操作,并返回一个WebSocket对象,该对象用于后续的websocket通信操作。当然,如果客户端请求并非为websocket操作时,转换将会失败,该方法会返回错误信息,使用时请注意判断方法的error返回值。 ReadMessage & WriteMessage 读取消息以及写入消息对应的是websocket的数据读取以及写入操作(ReadMessage & WriteMessage),需要注意的是这两个方法都有一个msgType的变量,表示请求读取及写入数据的类型,常见的两种数据类型为:字符串数据或者二进制数据。在使用过程中,由于接口双方都会约定统一的数据格式,因此读取和写入的msgType几乎都是一致的,所以在本示例中的返回消息时,数据类型参数直接使用的是读取到的msgType。如果需要支持HTTPS的WebSocket服务,只需要依赖的WebServer支持HTTPS即可,访问的WebSocket地址需要使用 wss:// 协议访问。以上客户端HTML5页面中的WebSocket访问地址需要修改为:wss://127.0.0.1:8199/wss。服务端示例代码:
package main
import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/glog"
)
var ctx = gctx.New()
func main() {
s := g.Server()
s.BindHandler("/wss", func(r *ghttp.Request) {
ws, err := r.WebSocket()
if err != nil {
glog.Error(ctx,err)
r.Exit()
}
for {
msgType, msg, err := ws.ReadMessage()
if err != nil {
return
}
if err = ws.WriteMessage(msgType, msg); err != nil {
return
}
}
})
s.SetServerRoot(gfile.MainPkgPath())
s.EnableHTTPS("../../https/server.crt", "../../https/server.key")
s.SetPort(8199)
s.Run()
}
我们首先执行示例代码main.go,随后访问页面 http://127.0.0.1:8199/,随意输入请求内容并提交,随后在服务端关闭程序。可以看到,页面会回显提交的内容信息,并且即时展示websocket的连接状态的改变,当服务端关闭时,客户端也会即时地打印出关闭信息。
gf框架的websocket模块并不会做同源检查(origin),也就是说,这种条件下的websocket允许完全跨域。
安全的校验需要由业务层来处理,安全校验主要包含以下几个方面:
origin的校验: 业务层在执行r.WebSocket()之前需要进行origin同源请求的校验;或者按照自定义的处理对请求进行校验(如果请求提交参数);如果未通过校验,那么调用r.Exit()终止请求。websocket通信数据校验: 数据通信往往都有一些自定义的数据结构,在这些通信数据中加上鉴权处理逻辑;gf框架示例项目中提供了基于WebSocket的聊天室案例,具体请查看:https://github.com/gogf/gf-demos
func main() {
client := ghttp.NewWebSocketClient()
client.HandshakeTimeout = time.Second // 设置超时时间
client.Proxy = http.ProxyFromEnvironment // 设置代理
client.TLSClientConfig = &tls.Config{} // 设置 tls 配置
conn, _, err := client.Dial("ws://127.0.0.1:9501", nil)
if err != nil {
panic(err)
}
defer conn.Close()
err = conn.WriteMessage(websocket.TextMessage, []byte("hello word"))
if err != nil {
panic(err)
}
mt, data, err := conn.ReadMessage()
if err != nil {
panic(err)
}
fmt.Println(mt, data)
}