move gee day1-day7 to gee-web
@@ -1,222 +1,21 @@
|
||||
# 7天用Go从零实现Web框架Gee
|
||||
# 7天用Go从零实现系列
|
||||
|
||||

|
||||
## 序言
|
||||
|
||||
7天能写什么呢?类似 gin 的 web 框架?类似 groupcache 的分布式缓存?或者一个简单的 Python 解释器?希望这个仓库能给你答案。
|
||||
|
||||
如果是 Go 语言的初学者,推荐先阅读 [Go 语言简明教程](https://geektutu.com/post/quick-golang.html)。
|
||||
推荐先阅读 **[Go 语言简明教程](https://geektutu.com/post/quick-golang.html)**,一篇文章了解Go的基本语法、并发编程,依赖管理等内容
|
||||
|
||||
Gee 的设计与实现参考了Gin,这个教程可以快速入门:[Go Gin简明教程](https://geektutu.com/post/quick-go-gin.html)。
|
||||
## 7天用Go从零实现Web框架Gee
|
||||
|
||||
## [教程目录](https://geektutu.com/post/gee.html)
|
||||
Gee 的设计与实现参考了Gin,[Go Gin简明教程](https://geektutu.com/post/quick-go-gin.html)可以快速入门。
|
||||
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html),[Code - Github](day1-http-base)
|
||||
- [第二天:上下文设计(Context)](https://geektutu.com/post/gee-day2.html),[Code - Github](day2-context)
|
||||
- [第三天:Tire树路由(Router)](https://geektutu.com/post/gee-day3.html),[Code - Github](day3-router)
|
||||
- [第四天:分组控制(Group)](https://geektutu.com/post/gee-day4.html),[Code - Github](day4-group)
|
||||
- [第五天:中间件(Middleware)](https://geektutu.com/post/gee-day5.html),[Code - Github](day5-middleware)
|
||||
- [第六天:HTML模板(Template)](https://geektutu.com/post/gee-day6.html),[Code - Github](day6-template)
|
||||
- [第七天:错误恢复(Panic Recover)](https://geektutu.com/post/gee-day7.html),[Code - Github](day7-panic-recover)
|
||||
#### [教程目录](https://geektutu.com/post/gee.html)
|
||||
|
||||
|
||||
## Day 1 - Static Route
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
|
||||
for k, v := range req.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 2 - Context Design
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
r.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
|
||||
r.POST("/login", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, &map[string]string{
|
||||
"username": c.PostForm("username"),
|
||||
"password": c.PostForm("password"),
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 3 - Dynamic Route
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
r.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
|
||||
r.GET("/assets/*filepath", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, gee.H{"filepath": c.Param("filepath")})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 4 - Nesting Group Control
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
v1 := r.Group("/v1")
|
||||
{
|
||||
v1.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
v1.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
}
|
||||
v2 := r.Group("/v2")
|
||||
{
|
||||
v2.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
v2.POST("/login", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, &map[string]string{
|
||||
"username": c.PostForm("username"),
|
||||
"password": c.PostForm("password"),
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 5 - Middleware
|
||||
|
||||
```go
|
||||
func onlyForV2() gee.HandlerFunc {
|
||||
return func(c *gee.Context) {
|
||||
// Start timer
|
||||
t := time.Now()
|
||||
// if a server error occurred
|
||||
c.Fail(500, "Internal Server Error")
|
||||
// Calculate resolution time
|
||||
log.Printf("[%d] %s in %v for group v2", c.StatusCode, c.Req.RequestURI, time.Since(t))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.Use(gee.Logger()) // global midlleware
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
v2 := r.Group("/v2")
|
||||
v2.Use(onlyForV2()) // v2 group middleware
|
||||
{
|
||||
v2.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
}
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 6 - HTML Template
|
||||
|
||||
```go
|
||||
type student struct {
|
||||
Name string
|
||||
Age int8
|
||||
}
|
||||
|
||||
func formatAsDate(t time.Time) string {
|
||||
year, month, day := t.Date()
|
||||
return fmt.Sprintf("%d-%02d-%02d", year, month, day)
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.Use(gee.Logger())
|
||||
r.SetFuncMap(template.FuncMap{
|
||||
"formatAsDate": formatAsDate,
|
||||
})
|
||||
r.LoadHTMLGlob("templates/*")
|
||||
r.Static("/assets", "./static")
|
||||
|
||||
stu1 := &student{Name: "Geektutu", Age: 20}
|
||||
stu2 := &student{Name: "Jack", Age: 22}
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "css.tmpl", nil)
|
||||
})
|
||||
r.GET("/students", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "arr.tmpl", gee.H{
|
||||
"title": "gee",
|
||||
"stuArr": [2]*student{stu1, stu2},
|
||||
})
|
||||
})
|
||||
|
||||
r.GET("/date", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "custom_func.tmpl", gee.H{
|
||||
"title": "gee",
|
||||
"now": time.Date(2019, 8, 17, 0, 0, 0, 0, time.UTC),
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 7 - Panic Recover
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.Default()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.String(http.StatusOK, "Hello Geektutu\n")
|
||||
})
|
||||
// index out of range for testing Recovery()
|
||||
r.GET("/panic", func(c *gee.Context) {
|
||||
names := []string{"geektutu"}
|
||||
c.String(http.StatusOK, names[100])
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
|
||||
```
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html),[Code - Github](gee-web/day1-http-base)
|
||||
- [第二天:上下文设计(Context)](https://geektutu.com/post/gee-day2.html),[Code - Github](gee-web/day2-context)
|
||||
- [第三天:Tire树路由(Router)](https://geektutu.com/post/gee-day3.html),[Code - Github](gee-web/day3-router)
|
||||
- [第四天:分组控制(Group)](https://geektutu.com/post/gee-day4.html),[Code - Github](gee-web/day4-group)
|
||||
- [第五天:中间件(Middleware)](https://geektutu.com/post/gee-day5.html),[Code - Github](gee-web/day5-middleware)
|
||||
- [第六天:HTML模板(Template)](https://geektutu.com/post/gee-day6.html),[Code - Github](gee-web/day6-template)
|
||||
- [第七天:错误恢复(Panic Recover)](https://geektutu.com/post/gee-day7.html),[Code - Github](gee-web/day7-panic-recover)
|
||||
@@ -0,0 +1,215 @@
|
||||
# 7天用Go从零实现Web框架Gee
|
||||
|
||||

|
||||
|
||||
## 教程目录
|
||||
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html)
|
||||
- [第二天:上下文设计(Context)](https://geektutu.com/post/gee-day2.html)
|
||||
- [第三天:Tire树路由(Router)](https://geektutu.com/post/gee-day3.html)
|
||||
- [第四天:分组控制(Group)](https://geektutu.com/post/gee-day4.html)
|
||||
- [第五天:中间件(Middleware)](https://geektutu.com/post/gee-day5.html)
|
||||
- [第六天:HTML模板(Template)](https://geektutu.com/post/gee-day6.html)
|
||||
- [第七天:错误恢复(Panic Recover)](https://geektutu.com/post/gee-day7.html)
|
||||
|
||||
## Day 1 - Static Route
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(w http.ResponseWriter, req *http.Request) {
|
||||
fmt.Fprintf(w, "URL.Path = %q\n", req.URL.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello", func(w http.ResponseWriter, req *http.Request) {
|
||||
for k, v := range req.Header {
|
||||
fmt.Fprintf(w, "Header[%q] = %q\n", k, v)
|
||||
}
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 2 - Context Design
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
r.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
|
||||
r.POST("/login", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, &map[string]string{
|
||||
"username": c.PostForm("username"),
|
||||
"password": c.PostForm("password"),
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 3 - Dynamic Route
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
r.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
|
||||
r.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
|
||||
r.GET("/assets/*filepath", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, gee.H{"filepath": c.Param("filepath")})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 4 - Nesting Group Control
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.New()
|
||||
v1 := r.Group("/v1")
|
||||
{
|
||||
v1.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
v1.GET("/hello", func(c *gee.Context) {
|
||||
// expect /hello?name=geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Query("name"), c.Path)
|
||||
})
|
||||
}
|
||||
v2 := r.Group("/v2")
|
||||
{
|
||||
v2.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
v2.POST("/login", func(c *gee.Context) {
|
||||
c.JSON(http.StatusOK, &map[string]string{
|
||||
"username": c.PostForm("username"),
|
||||
"password": c.PostForm("password"),
|
||||
})
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 5 - Middleware
|
||||
|
||||
```go
|
||||
func onlyForV2() gee.HandlerFunc {
|
||||
return func(c *gee.Context) {
|
||||
// Start timer
|
||||
t := time.Now()
|
||||
// if a server error occurred
|
||||
c.Fail(500, "Internal Server Error")
|
||||
// Calculate resolution time
|
||||
log.Printf("[%d] %s in %v for group v2", c.StatusCode, c.Req.RequestURI, time.Since(t))
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.Use(gee.Logger()) // global midlleware
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "<h1>Hello Gee</h1>")
|
||||
})
|
||||
|
||||
v2 := r.Group("/v2")
|
||||
v2.Use(onlyForV2()) // v2 group middleware
|
||||
{
|
||||
v2.GET("/hello/:name", func(c *gee.Context) {
|
||||
// expect /hello/geektutu
|
||||
c.String(http.StatusOK, "hello %s, you're at %s\n", c.Param("name"), c.Path)
|
||||
})
|
||||
}
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 6 - HTML Template
|
||||
|
||||
```go
|
||||
type student struct {
|
||||
Name string
|
||||
Age int8
|
||||
}
|
||||
|
||||
func formatAsDate(t time.Time) string {
|
||||
year, month, day := t.Date()
|
||||
return fmt.Sprintf("%d-%02d-%02d", year, month, day)
|
||||
}
|
||||
|
||||
func main() {
|
||||
r := gee.New()
|
||||
r.Use(gee.Logger())
|
||||
r.SetFuncMap(template.FuncMap{
|
||||
"formatAsDate": formatAsDate,
|
||||
})
|
||||
r.LoadHTMLGlob("templates/*")
|
||||
r.Static("/assets", "./static")
|
||||
|
||||
stu1 := &student{Name: "Geektutu", Age: 20}
|
||||
stu2 := &student{Name: "Jack", Age: 22}
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "css.tmpl", nil)
|
||||
})
|
||||
r.GET("/students", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "arr.tmpl", gee.H{
|
||||
"title": "gee",
|
||||
"stuArr": [2]*student{stu1, stu2},
|
||||
})
|
||||
})
|
||||
|
||||
r.GET("/date", func(c *gee.Context) {
|
||||
c.HTML(http.StatusOK, "custom_func.tmpl", gee.H{
|
||||
"title": "gee",
|
||||
"now": time.Date(2019, 8, 17, 0, 0, 0, 0, time.UTC),
|
||||
})
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
|
||||
## Day 7 - Panic Recover
|
||||
|
||||
```go
|
||||
func main() {
|
||||
r := gee.Default()
|
||||
r.GET("/", func(c *gee.Context) {
|
||||
c.String(http.StatusOK, "Hello Geektutu\n")
|
||||
})
|
||||
// index out of range for testing Recovery()
|
||||
r.GET("/panic", func(c *gee.Context) {
|
||||
names := []string{"geektutu"}
|
||||
c.String(http.StatusOK, names[100])
|
||||
})
|
||||
|
||||
r.Run(":9999")
|
||||
}
|
||||
```
|
||||
@@ -24,7 +24,7 @@ github: https://github.com/geektutu/7days-golang
|
||||
|
||||
Go语言内置了 `net/http`库,封装了HTTP网络编程的基础的接口,我们实现的`Gee` Web 框架便是基于`net/http`的。我们接下来通过一个例子,简单介绍下这个库的使用。
|
||||
|
||||
**[day1-http-base/base1/main.go](https://github.com/geektutu/7days-golang/tree/master/day1-http-base/base1)**
|
||||
**[day1-http-base/base1/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day1-http-base/base1)**
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -82,7 +82,7 @@ func ListenAndServe(address string, h Handler) error
|
||||
|
||||
第二个参数的类型是什么呢?通过查看`net/http`的源码可以发现,`Handler`是一个接口,需要实现方法 _ServeHTTP_ ,也就是说,只要传入任何实现了 _ServerHTTP_ 接口的实例,所有的HTTP请求,就都交给了该实例处理了。马上来试一试吧。
|
||||
|
||||
**[day1-http-base/base2/main.go](https://github.com/geektutu/7days-golang/tree/master/day1-http-base/base2)**
|
||||
**[day1-http-base/base2/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day1-http-base/base2)**
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -135,7 +135,7 @@ main.go
|
||||
|
||||
### main.go
|
||||
|
||||
**[day1-http-base/base3/main.go](https://github.com/geektutu/7days-golang/tree/master/day1-http-base/base3)**
|
||||
**[day1-http-base/base3/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day1-http-base/base3)**
|
||||
|
||||
```go
|
||||
package main
|
||||
@@ -167,7 +167,7 @@ func main() {
|
||||
|
||||
### gee.go
|
||||
|
||||
**[day1-http-base/base3/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/day1-http-base/base3)**
|
||||
**[day1-http-base/base3/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day1-http-base/base3)**
|
||||
|
||||
```go
|
||||
package gee
|
||||
@@ -25,7 +25,7 @@ github: https://github.com/geektutu/7days-golang
|
||||
|
||||
为了展示第二天的成果,我们看一看在使用时的效果。
|
||||
|
||||
[day2-context/main.go](https://github.com/geektutu/7days-golang/tree/master/day2-context)
|
||||
[day2-context/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day2-context)
|
||||
|
||||
|
||||
```go
|
||||
@@ -90,7 +90,7 @@ c.JSON(http.StatusOK, gee.H{
|
||||
|
||||
### 具体实现
|
||||
|
||||
[day2-context/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/day2-context)
|
||||
[day2-context/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day2-context)
|
||||
|
||||
```go
|
||||
type H map[string]interface{}
|
||||
@@ -168,7 +168,7 @@ func (c *Context) HTML(code int, html string) {
|
||||
|
||||
我们将和路由相关的方法和结构提取了出来,放到了一个新的文件中`router.go`,方便我们下一次对 router 的功能进行增强,例如提供动态路由的支持。 router 的 handle 方法作了一个细微的调整,即 handler 的参数,变成了 Context。
|
||||
|
||||
[day2-context/gee/router.go](https://github.com/geektutu/7days-golang/tree/master/day2-context)
|
||||
[day2-context/gee/router.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day2-context)
|
||||
|
||||
```go
|
||||
type router struct {
|
||||
@@ -197,7 +197,7 @@ func (r *router) handle(c *Context) {
|
||||
|
||||
## 框架入口
|
||||
|
||||
[day2-context/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/day2-context)
|
||||
[day2-context/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day2-context)
|
||||
|
||||
```go
|
||||
// HandlerFunc defines the request handler used by gee
|
||||
@@ -52,7 +52,7 @@ HTTP请求的路径恰好是由`/`分隔的多段构成的,因此,每一段
|
||||
|
||||
首先我们需要设计树节点上应该存储那些信息。
|
||||
|
||||
**[day3-router/gee/trie.go](https://github.com/geektutu/7days-golang/tree/master/day3-router/gee)**
|
||||
**[day3-router/gee/trie.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day3-router/gee)**
|
||||
|
||||
```go
|
||||
type node struct {
|
||||
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@@ -49,7 +49,7 @@ v1.GET("/", func(c *gee.Context) {
|
||||
|
||||
所以,最后的 Group 的定义是这样的:
|
||||
|
||||
**[day4-group/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/day4-group/gee)**
|
||||
**[day4-group/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day4-group/gee)**
|
||||
|
||||
```go
|
||||
RouterGroup struct {
|
||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -33,7 +33,7 @@ github: https://github.com/geektutu/7days-golang
|
||||
|
||||
Gee 的中间件的定义与路由映射的 Handler 一致,处理的输入是`Context`对象。插入点是框架接收到请求初始化`Context`对象后,允许用户使用自己定义的中间件做一些额外的处理,例如记录日志等,以及对`Context`进行二次加工。另外通过调用`(*Context).Next()`函数,中间件可等待用户自己定义的 `Handler`处理结束后,再做一些额外的操作,例如计算本次处理所用时间等。即 Gee 的中间件支持用户在请求被处理的前后,做一些额外的操作。举个例子,我们希望最终能够支持如下定义的中间件,`c.Next()`表示等待执行其他的中间件或用户的`Handler`:
|
||||
|
||||
****[day4-group/gee/logger.go](https://github.com/geektutu/7days-golang/tree/master/day5-middleware/gee)****
|
||||
****[day4-group/gee/logger.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day5-middleware/gee)****
|
||||
|
||||
```go
|
||||
func Logger() HandlerFunc {
|
||||
@@ -56,7 +56,7 @@ func Logger() HandlerFunc {
|
||||
|
||||
为此,我们给`Context`添加了2个参数,定义了`Next`方法:
|
||||
|
||||
**[day4-group/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/day5-middleware/gee)**
|
||||
**[day4-group/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day5-middleware/gee)**
|
||||
|
||||
```go
|
||||
type Context struct {
|
||||
@@ -130,7 +130,7 @@ func B(c *Context) {
|
||||
|
||||
- 定义`Use`函数,将中间件应用到某个 Group 。
|
||||
|
||||
**[day4-group/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/day5-middleware/gee)**
|
||||
**[day4-group/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day5-middleware/gee)**
|
||||
|
||||
```go
|
||||
// Use is defined to add middleware to the group
|
||||
@@ -155,7 +155,7 @@ ServeHTTP 函数也有变化,当我们接收到一个具体请求时,要判
|
||||
|
||||
- handle 函数中,将从路由匹配得到的 Handler 添加到 `c.handlers`列表中,执行`c.Next()`。
|
||||
|
||||
**[day4-group/gee/router.go](https://github.com/geektutu/7days-golang/tree/master/day5-middleware/gee)**
|
||||
**[day4-group/gee/router.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day5-middleware/gee)**
|
||||
|
||||
```go
|
||||
func (r *router) handle(c *Context) {
|
||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
@@ -36,7 +36,7 @@ github: https://github.com/geektutu/7days-golang
|
||||
|
||||
找到文件后,如何返回这一步,`net/http`库已经实现了。因此,gee 框架要做的,仅仅是解析请求的地址,映射到服务器上文件的真实地址,交给`http.FileServer`处理就好了。
|
||||
|
||||
[day6-template/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/day6-template/gee)
|
||||
[day6-template/gee/gee.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day6-template/gee)
|
||||
|
||||
```go
|
||||
// create static handler
|
||||
@@ -103,7 +103,7 @@ func (engine *Engine) LoadHTMLGlob(pattern string) {
|
||||
|
||||
接下来,对原来的 `(*Context).HTML()`方法做了些小修改,使之支持根据模板文件名选择模板进行渲染。
|
||||
|
||||
[day6-template/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/day6-template/gee)
|
||||
[day6-template/gee/context.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day6-template/gee)
|
||||
|
||||
```go
|
||||
func (c *Context) HTML(code int, name string, data interface{}) {
|
||||
@@ -140,7 +140,7 @@ func (c *Context) HTML(code int, name string, data interface{}) {
|
||||
</html>
|
||||
```
|
||||
|
||||
[day6-template/main.go](https://github.com/geektutu/7days-golang/tree/master/day6-template/gee)
|
||||
[day6-template/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day6-template/gee)
|
||||
|
||||
```go
|
||||
type student struct {
|
||||
|
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
@@ -168,7 +168,7 @@ func Recovery() HandlerFunc {
|
||||
|
||||
你可能注意到,这里有一个 *trace()* 函数,这个函数是用来获取触发 panic 的堆栈信息,完整代码如下:
|
||||
|
||||
[day7-panic-recover/gee/recovery.go](https://github.com/geektutu/7days-golang/tree/master/day7-panic-recover)
|
||||
[day7-panic-recover/gee/recovery.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day7-panic-recover)
|
||||
|
||||
```go
|
||||
package gee
|
||||
@@ -219,7 +219,7 @@ func Recovery() HandlerFunc {
|
||||
|
||||
## 使用 Demo
|
||||
|
||||
[day7-panic-recover/main.go](https://github.com/geektutu/7days-golang/tree/master/day7-panic-recover)
|
||||
[day7-panic-recover/main.go](https://github.com/geektutu/7days-golang/tree/master/gee-web/day7-panic-recover)
|
||||
|
||||
```go
|
||||
package main
|
||||
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
@@ -62,13 +62,13 @@ func handler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
## 目录
|
||||
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day1-http-base)
|
||||
- [第二天:上下文设计(Context)](https://geektutu.com/post/gee-day2.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day2-context)
|
||||
- [第三天:Tire树路由(Router)](https://geektutu.com/post/gee-day3.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day3-router)
|
||||
- [第四天:分组控制(Group)](https://geektutu.com/post/gee-day4.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day4-group)
|
||||
- [第五天:中间件(Middleware)](https://geektutu.com/post/gee-day5.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day5-middleware)
|
||||
- [第六天:HTML模板(Template)](https://geektutu.com/post/gee-day6.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day6-template)
|
||||
- [第七天:错误恢复(Panic Recover)](https://geektutu.com/post/gee-day7.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/day7-panic-recover)
|
||||
- [第一天:前置知识(http.Handler接口)](https://geektutu.com/post/gee-day1.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day1-http-base)
|
||||
- [第二天:上下文设计(Context)](https://geektutu.com/post/gee-day2.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day2-context)
|
||||
- [第三天:Tire树路由(Router)](https://geektutu.com/post/gee-day3.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day3-router)
|
||||
- [第四天:分组控制(Group)](https://geektutu.com/post/gee-day4.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day4-group)
|
||||
- [第五天:中间件(Middleware)](https://geektutu.com/post/gee-day5.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day5-middleware)
|
||||
- [第六天:HTML模板(Template)](https://geektutu.com/post/gee-day6.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day6-template)
|
||||
- [第七天:错误恢复(Panic Recover)](https://geektutu.com/post/gee-day7.html),[Code - Github](https://github.com/geektutu/7days-golang/tree/master/gee-web/day7-panic-recover)
|
||||
|
||||
## 推荐阅读
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |