geektutu
gee 框架
HTTP 基础
核心
1
2
3
|
http.HandleFunc("/", indexHandler)
http.HandleFunc("/hello", helloHandler)
log.Fatal(http.ListenAndServe(":9999", nil))
|
通过捆绑路径和 url
类型为 w http.ResponseWriter, req *http.Request
实现方法 ServeHTTP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
type Engine struct{}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
switch req.URL.Path {
case "/":
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
case "/hello":
for k, v := range req.Header {
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
}
default:
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
func main() {
engine := new(Engine)
log.Fatal(http.ListenAndServe(":9999", engine))
}
|
通过定义 Engine 结构体实现 ServeHTTP 再传入 http.ListenAndServe 第二个参数,ServeHTTP 封装了两个路径
封装 gee 包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
// HandlerFunc defines the request handler used by gee
type HandlerFunc func(http.ResponseWriter, *http.Request)
// Engine implement the interface of ServeHTTP
type Engine struct {
router map[string]HandlerFunc
}
// New is the constructor of gee.Engine
func New() *Engine {
return &Engine{router: make(map[string]HandlerFunc)}
}
func (engine *Engine) addRoute(method string, pattern string, handler HandlerFunc) {
key := method + "-" + pattern
engine.router[key] = handler
}
// GET defines the method to add GET request
func (engine *Engine) GET(pattern string, handler HandlerFunc) {
engine.addRoute("GET", pattern, handler)
}
// POST defines the method to add POST request
func (engine *Engine) POST(pattern string, handler HandlerFunc) {
engine.addRoute("POST", pattern, handler)
}
// Run defines the method to start a http server
func (engine *Engine) Run(addr string) (err error) {
return http.ListenAndServe(addr, engine)
}
func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) {
key := req.Method + "-" + req.URL.Path
if handler, ok := engine.router[key]; ok {
handler(w, req)
} else {
fmt.Fprintf(w, "404 NOT FOUND: %s\n", req.URL)
}
}
|
定义结构体时创建一个 router 的 map 将原先 func(w http.ResponseWriter, req *http.Request)放入 HandlerFunc 中
addRoute 将 method + “-” + pattern 构造成 router 的 key,value 为 handler
方法只需要传入 engine.addRoute(“GET”, pattern, handler)
通过 Run 来监听 http.ListenAndServe(addr, engine)
ServeHTTP 构造 key := req.Method + “-” + req.URL.Path,判断是否在 router 中
上下文
context
1
2
3
4
|
r := gee.New()
r.GET("/", func(c *gee.Context) {
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
})
|
将 context 作为匿名函数放进 Handler
map[string]interface{}起了一个别名 gee.H,构建 JSON 数据时,可以直接封装
1
2
3
4
|
c.JSON(http.StatusOK, gee.H{
"username": c.PostForm("username"),
"password": c.PostForm("password"),
})
|
router
将 addrouter 拿出修改为支持动态路由,handle 参数变为 context
gee
ServeHTTP 通过 router 的 handle 接管 context
前缀树路由
定义节点
1
2
3
4
5
6
|
type node struct {
pattern string // 待匹配路由,例如 /p/:lang
part string // 路由中的一部分,例如 :lang
children []*node // 子节点,例如 [doc, tutorial, intro]
isWild bool // 是否精确匹配,part 含有 : 或 * 时为true
}
|
trie
重点匹配*和:符号进行动态匹配,第一个匹配成功的节点用于插入,递归每一层如果没有 part 新建一个,匹配到末节点才会成功,所有匹配成功的点用于查找
router
handlers 存储每种请求方式,getroute 解析*和:,返回一个 map
context
通过 c.Param(“lang”)获取值
分组
将路径划分为组,需要知道父亲节点
1
2
3
4
5
|
r := gee.New()
v1 := r.Group("/v1")
v1.GET("/", func(c *gee.Context) {
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
})
|
gee
将 Engine 作为最顶层的分组,也就是说 Engine 拥有 RouterGroup 所有的能力
中间件
通过调用(*Context).Next()函数,中间件可等待用户自己定义的 Handler 处理结束后,再做一些额外的操作,例如计算本次处理所用时间等
需要注意 next 的执行顺序,按照 handler 为准
gee
定义 Use 函数到 group
可以给全局用也可以单独定义一个 group