Gin 框架的学习资料

Go 内置了 http.Server 的实现,如下:

package main

import (
    "log"
    "net/http"
    "time"
)

type NewHandler struct{}

func (s *NewHandler) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
    // 根据 req 查找对应的 handler
    if req.URL.Path == "/hello2" {
        writer.Write([]byte("Hello2 World!"))
    }
}

func newServer(addr string) {
    s := &http.Server{
        Addr:              addr,
        Handler:           nil,
        TLSConfig:         nil,
        ReadTimeout:       0,
        ReadHeaderTimeout: 0,
        WriteTimeout:      0,
        IdleTimeout:       0,
        MaxHeaderBytes:    0,
        TLSNextProto:      nil,
        ConnState:         nil,
        ErrorLog:          nil,
        BaseContext:       nil,
        ConnContext:       nil,
    }
    s.Handler = &NewHandler{}
    log.Fatal(s.ListenAndServe())
}

func main() {
    // $ curl 127.0.0.1:8082/hello2
    // Hello2 World!%
    go newServer(":8082")
    time.Sleep(1000 * time.Second)
}

可以看到关键是:当一个 http 请求到达时,ServerHTTP() 怎样快速找到对应的处理函数进行响应。Gin 最主要功能就是实现 request 与处理函数直接映射,也就是 router 管理。

package main

import (
    "github.com/gin-gonic/gin"
    "net/http"
    "time"
)

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })

    //r.Run() // listen and serve on 0.0.0.0:8080
    s := &http.Server{
        Addr:           ":8080",
        Handler:        r,
        ReadTimeout:    10 * time.Second,
        WriteTimeout:   10 * time.Second,
        MaxHeaderBytes: 1 << 20,
    }
    s.ListenAndServe()
}

Gin 选用 Radix_tree 管理路由表,Radis_tree 是“树”的一种,实现了不定长字符串的查找,叶子节点中存放的 handler 函数,非叶子节点指向子节点,并在“边”中标记前缀字符:

因为每条边中包含不止一个字符,所有 Radis_tree 的高度降低,查找效率提高。

radis_tree

参考资料

  1. 李佶澳的博客
  2. gin-gonic/gin
  3. gin web framework
  4. Radix_tree