V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
Nazz
V2EX  ›  程序员

在 websocket app 中使用 gin-like API 处理请求

  •  
  •   Nazz · 2023-02-06 16:30:15 +08:00 · 767 次点击
    这是一个创建于 685 天前的主题,其中的信息可能已经有所发展或是发生改变。

    连续肝了几天, 厚着脸皮再发一次. 目前测试覆盖率已经到达了 95%, 欢迎大家 star, issue 和 PR

    项目地址: https://github.com/lxzan/uRouter

    express, koa, gin 致敬!

    特性

    • 通用的 web 路由系统抽象, 核心部分无依赖
    • hashmap 实现的静态路由, 拒绝路径中夹带参数
    • 提供洋葱模型的中间件, 路由组
    • 适配std http, lxzan/gws, gorilla/websocket

    Demo

    • server
    package main
    
    import (
    	"github.com/lxzan/gws"
    	"github.com/lxzan/uRouter"
    	gwsAdapter "github.com/lxzan/uRouter/contrib/adapter/gws"
    	httpAdapter "github.com/lxzan/uRouter/contrib/adapter/http"
    	"log"
    	"net/http"
    )
    
    func main() {
    	var router = uRouter.New()
    	router.Use(uRouter.Recovery(), uRouter.AccessLog())
    
    	var upgrader = gws.NewUpgrader(func(c *gws.Upgrader) {
    		c.EventHandler = NewWebSocketHandler(router, gwsAdapter.NewAdapter(router))
    	})
    
    	router.On("/connect", func(ctx *uRouter.Context) {
    		r := ctx.Request.Raw
    		w := ctx.Writer.Raw()
    		socket, err := upgrader.Accept(w.( http.ResponseWriter), r.(*http.Request))
    		if err != nil {
    			log.Println(err.Error())
    			return
    		}
    		socket.Listen()
    	})
    
    	router.Display()
    	if err := http.ListenAndServe(":3000", httpAdapter.NewAdapter(router)); err != nil {
    		log.Fatalln(err.Error())
    	}
    }
    
    func NewWebSocketHandler(router *uRouter.Router, adapter *gwsAdapter.Adapter) *WebSocketHandler {
    	h := &WebSocketHandler{
    		adapter: adapter,
    		router:  router,
    	}
    	group := router.Group("", uRouter.Protocol(uRouter.ProtocolWebSocket))
    	group.On("/greet", h.Greet)
    	return h
    }
    
    type WebSocketHandler struct {
    	gws.BuiltinEventEngine
    	adapter *gwsAdapter.Adapter
    	router  *uRouter.Router
    }
    
    func (c *WebSocketHandler) OnMessage(socket *gws.Conn, message *gws.Message) {
    	if err := c.adapter.ServeWebSocket(socket, message); err != nil {
    		log.Println(err.Error())
    	}
    }
    
    func (c *WebSocketHandler) Greet(ctx *uRouter.Context) {
    	var req = uRouter.Any{}
    	if err := ctx.BindJSON(&req); err != nil {
    		log.Println(err.Error())
    		return
    	}
    	ctx.Writer.Header().Set(uRouter.ContentType, uRouter.MimeJson)
    	_ = ctx.WriteJSON(int(gws.OpcodeText), req)
    }
    
    • client
    let ws = new WebSocket('ws://127.0.0.1:3000/connect')
    ws.send('0019{"X-Path":"/greet"}{"hello":"你好, 少侠"}');
    
    7 条回复    2023-02-06 20:14:54 +08:00
    learningman
        1
    learningman  
       2023-02-06 16:50:40 +08:00   ❤️ 1
    “hashmap 实现的静态路由, 拒绝路径中夹带参数”
    好像还挺自豪。。。
    Nazz
        2
    Nazz  
    OP
       2023-02-06 16:52:08 +08:00
    @learningman 你以为 restful 表达能力很强性能很好吗
    learningman
        3
    learningman  
       2023-02-06 16:59:14 +08:00
    @Nazz #2 所以框架的应该教用户做事吗?
    learningman
        4
    learningman  
       2023-02-06 17:01:02 +08:00
    @Nazz #2 字典树肯定没 hashmap 跑的快啊,但还是那句话,框架应该教用户做事吗?
    Nazz
        5
    Nazz  
    OP
       2023-02-06 17:09:02 +08:00
    @learningman 每个项目都会有作者的个人风格. 我认为, 对于 api server, JSON-RPC 抽象比 RESTful 好得多
    Nazz
        6
    Nazz  
    OP
       2023-02-06 17:09:49 +08:00
    @learningman 用户有选择自己喜欢的库的自由
    Nazz
        7
    Nazz  
    OP
       2023-02-06 20:14:54 +08:00 via Android
    @learningman 不仅仅是数据结构本身的性能,动态路由不方便做监控和日志分析
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5996 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 02:03 · PVG 10:03 · LAX 18:03 · JFK 21:03
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.