Go Web开发(Gin框架)

写在开头

这篇博客即属于博客也属于笔记,内容大部分来自于go编程课老师的Go Web开发(Gin 框架)简易入门教程。
本人做一些笔记整理成这篇博客。

net/http标准库

Go语言内置的net/http包,为我们提供了基础的路由函数组合和丰富的功能函数。
只是需要简单的API编写,net/http就完全足够了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

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

func main() {
//该方法接收一个路由匹配的字符串,以及一个func(ResponseWriter,*Request)类型的函数
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8000", nil))
}

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
fmt.Fprintf(w, "helloworld")

}
//func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
//注册默认路由,第一个参数指的是请求路径,第二个参数是一个函数类型,表示这个请求需要处理的事情。

进阶

gin框架

Gin是一个用Go(Golang)编写的HTTP web框架。它是一个类似于martini但拥有更好性能的API框架,由于httprouter,速度提高了近40倍。

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "github.com/gin-gonic/gin"

func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{"message": "pong"})
})
r.Run()
//默认监听本地8080端口,如需更改写法为r.Run(":9000")
}

路由

输出渲染格式

gin可以很方便的渲染输出数据的格式

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
42
43
44
45
46
47
package main

import (
"net/http"

"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.GET("/someString", func(c *gin.Context) {
//渲染成String
c.String(http.StatusOK, "string")
})

r.GET("/someJSON", func(c *gin.Context) {
//渲染成JSON
c.JSON(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
})

r.GET("/moreJSON", func(c *gin.Context) {
var msg struct {
Name string `json:"user"`
Message string
Number int
}

msg.Name = "Lena"
msg.Message = "hey"
msg.Number = 123
//渲染成JSON
c.JSON(http.StatusOK, msg)
})

r.GET("/someXML", func(c *gin.Context) {
//渲染成XML
c.XML(http.StatusOK, gin.H{"message": "Hey", "status": http.StatusOK})
})

r.GET("/someYAML", func(c *gin.Context) {
//YAML是“YAML Ain't a Markup Language的缩写,中文名为:另一种标记语言”
//是一个可读性高,用来表达数据序列化的格式。
c.YAML(http.StatusOK, gin.H{"message": "Hey", "status": http.StatusOK})
})

r.Run()
}

中间件

1
r := gin.Default()

Default函数会默认绑定准备好的中间件,LoggerRecovery,它们分别帮助我们打印日志输出和painc处理

1
2
3
4
5
6
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery())
return engine
}

从中可以看出,Gin的中间件是通过Use方法设置的,它接收一个可变参数,所以我们同时可以设置多个中间件。

1
2
3
4
5
6
func(engine *Engine) Use(middleware ...HandlerFunc) IRoutes {
engine.RouterGroup.Use(middleware...)
engine.rebuild404Handlers()
engine.rebuild405Handlers()
return engine
}

而一个Gin的中间件,其实就是Gin定义的一个HandlerFunc

现在来自定义一个自己的中间件。

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
package main

import (
"fmt"
"time"

"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.Use(requestTime())
r.GET("/", func(c *gin.Context) {
fmt.Println("I'm here, hello")
c.String(200, "hello")
})
r.Run(":8888")
}

func requestTime() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
fmt.Println("这里被我拦截住了")
fmt.Println("因为调用了c.Next() 我现在要走了")
c.Next()
fmt.Println("我又回来了")
fmt.Println(time.Since(start))
}
}

c.Next()

立即执行下一个HandlerFunc,完后跳转回来继续执行c.Next()接下去的代码

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
package main

import (
"fmt"

"github.com/gin-gonic/gin"
)

func main() {
r := gin.New()
r.Use(mymiddleware())
r.Use(mymiddleware2())
r.GET("/", func(c *gin.Context) {
fmt.Println("test in")
c.String(200, "自我定义中间件测试成功")

fmt.Println("test out")

})

r.Run()

}

func mymiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("mml 1 in")
//调用后续的处理函数
//c.Next()
fmt.Println("mml 1 out")
}
}

func mymiddleware2() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("mml 2 in")
c.Next()
fmt.Println("mml 2 out")
}
}

输出结果

c.Next()相关1

c.Next()相关2

c.Abort()

阻断执行下一个HandlerFunc,仅会执行接下去的代码,常用于权限控制拦截操作。

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
package main

import (
"fmt"
"net/http"

"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.Use(authority())
//如果post请求中为admin,调用c.Next()方法,执行后续的处理函数
//否则调用c.Abort()方法2,阻止执行后续的处理函数,并执行中间件中的拦截方法
r.GET("/path/:name", func(c *gin.Context) {
fmt.Println("欢迎")
c.String(http.StatusOK, "Hello %s", c.Param("name"))
})
r.Run(":8090")
}

func authority() gin.HandlerFunc {
return func(c *gin.Context) {
isAdmain := c.Param("name") == "admin"
if isAdmain {
//执行后续的处理函数
c.Next()
} else {
//阻止执行后续的处理函数
c.Abort()
c.String(http.StatusOK, "sorry, you cann't in")
}
fmt.Println("end")
}
}

c.Set(key, value) 和 c.Get(key)

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
package main

import (
"fmt"

"net/http"

"github.com/gin-gonic/gin"
)

func main() {
r := gin.Default()
r.Use(authority2())
r.GET("/", func(c *gin.Context) {
value, ok := c.Get("key")
if ok {
fmt.Println(value)
}
c.String(http.StatusOK, "hello")
})
r.Run(":8099")
}

func authority2() gin.HandlerFunc {
return func(c *gin.Context) {
c.Set("key", "你好")
c.Next()
}
}
文章作者: 牧尾伊織
文章链接: http://example.com/2021/10/26/note/GoWeb开发/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Makiori's blog