十行代码增强Gin处理Websocket的能力

快速开始

最近几年Golang写的比较多,HTTP使用Gin,简单高效。今天我们来增强Gin处理Websocket的能力,先上代码:

package main

import (
    "net/http"
    "time"

    "github.com/gin-gonic/gin"

    "github.com/wonli/aqi"
    "github.com/wonli/aqi/ws"
)

func main() {
    app := aqi.Init(
       aqi.ConfigFile("config.yaml"),
       aqi.HttpServer("Aqi", "port"),
    )

    engine := gin.Default()
    // Gin路由
    engine.GET("/", func(c *gin.Context) {
       c.String(http.StatusOK, "Hi aqi!")
    })

    // Websocket入口
    engine.GET("/ws", func(c *gin.Context) {
       ws.HttpHandler(c.Writer, c.Request)
    })

    // Websoket路由注册
    wsr := ws.NewRouter()
    wsr.Add("hi", func(a *ws.Context) {
       a.Send(ws.H{
          "hi": time.Now(),
       })
    })

    app.WithHttpServer(engine)
    app.Start()
}

使用方法很简单,先初始化路由ws.NewRouter(),然后使用Add方法注册, 最后将engine作为参数传给app.WithHttpServer(engine)。这样在愉快的使用gin处理HTTP的时候,也可以愉快的处理Websocket了。

wsr := ws.NewRouter()
wsr.Add("hi", func(a *ws.Context) {
    a.Send(ws.H{
       "hi": time.Now(),
    })
})

我们使用wscat来作为websocket客户端,在terminal中新开一个tab,使用 wscat -c ws://127.0.0.1:2015/ws 与服务端建立连接后,输入{"action":"hi"}后可以看到服务器返回了当前时间, 运行截图如下:

处理输入参数

我们可以很方便的在业务代码中处理用户输入,接收用户输入的ID再原样返回:

wsr.Add("hi", func(a *ws.Context) {
    id := a.GetInt("id")
    a.Send(ws.H{
       "hi": time.Now(),
       "id": id,
    })
})

我们已经在业务代码中成功接收和处理输入的ID了

*ws.Context中,我们封装了一系列方法来方便的处理输入输出,Get开头的系列方法获取指定用户输入的参数,比如ID,Name等。Binding开头系列用于将用户输入转换为一个struct,这是最常用的。Send开头用于发送数据到客户端,具体请查看代码。

使用中间件

Aqi中使用中间件跟Gin类似,先注册一个中间件, 在服务panic的时候收集打印日志,并返回错误码:

package middlewares

import (
    "runtime/debug"

    "github.com/wonli/aqi/logger"
    "github.com/wonli/aqi/ws"
)

func Recovery() ws.HandlerFunc {
    return func(a *ws.Context) {
       defer func() {
          if err := recover(); err != nil {
             // 获取 panic 发生的堆栈跟踪
             stack := debug.Stack()
             logger.SugarLog.Errorf("Panic happened: %s \n %s\n", err, stack)

             a.SendCode(30, "服务维护中")
             a.Abort()
          }
       }()

       a.Next()
    }
}

在业务代码中使用中间件:

wsr := ws.NewRouter()
wsr.Use(middlewares.Recovery()).Add("hi", func(a *ws.Context) {
    panic("hi")
})

当然也可以这样:

wsr := ws.NewRouter()
r1 := wsr.Use(middlewares.Recovery())
{
    r1.Add("hi", func(a *ws.Context) {
       panic("hi")
    })
}

当我们程序panic的时候,不会终止进程,而是返回对应的错误信息给客户端,运行截图:

有没有觉得很方便,目前已经开源,感兴趣的小伙伴请点个start吧,希望大家多提意见,一起来完善,谢谢~

github.com/wonli/aqi

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!