赞
踩
gin是用go语言开发的一个web框架,简单易用,是一个轻量级框架。Gin是Golang的一个web框架,封装优雅API友好,源码注释比较明确。借助Gin框架开发web服务,不仅可以省去很多常用的封装带来的时间,也有助于团队的编码风格和形成规范。
安装Gin
go get -u github.com/gin-gonic/gin
使用Gin
import "github.com/gin-gonic/gin"
示例代码:
import (
"github.com/gin-gonic/gin"
"net/http"
)
func main(){
router := gin.Default()
router.GET("/", func(c *gin.Context) {
c.String(http.StatusOK, "Hello World")
})
router.Run(":8000")
}
Gin提供了分组路由的功能,能够让代码更加模块化。
v1 := router.Group("/v1")
v1.GET("/login", func(c *gin.Context) {
c.String(http.StatusOK, "v1 login")
})
v2 := router.Group("/v2")
v2.GET("/login", func(c *gin.Context) {
c.String(http.StatusOK, "v2 login")
})
Gin提供了中间件的功能,中间件分为全局中间件、单个路由中间件和分组中间件。
中间件只对注册过的路由函数起作用,对于分组路由使用中间件可以限定中间件的作用范围。
中间件的功能主要用于请求处理之前的鉴权、通用参数解析 以及在请求处理之后统一的响应构建等等。
func MiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("before middleware")
c.Set("request", "clinet_request")
c.Next()
fmt.Println("before middleware")
}
}
router.Use(MiddleWare())
router.GET("/middleware", func(c *gin.Context) {
request := c.MustGet("request").(string)
req, _ := c.Get("request")
c.JSON(http.StatusOK, gin.H{
"middile_request": request,
"request": req,
})
})
router.Use(MiddleWare()) 表示所有的路由都会经过MiddleWare()函数处理。
func MiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("before middleware")
c.Set("request", "clinet_request")
c.Next()
fmt.Println("before middleware")
}
}
router.GET("/before", MiddleWare(), func(c *gin.Context) {
request := c.MustGet("request").(string)
c.JSON(http.StatusOK, gin.H{
"middile_request": request,
})
})
router.GET(“/before”, MiddleWare(), func(c gin.Context) 只有*/before**这个路由会经过MiddleWare()函数处理。
func MiddleWare() gin.HandlerFunc {
return func(c *gin.Context) {
fmt.Println("before middleware")
c.Set("request", "clinet_request")
c.Next()
fmt.Println("before middleware")
}
}
authorized := router.Group("/")
authorized.Use(MyMiddelware())
authorized.POST("/login", loginEndpoint)
authorized := router.Group(“/”) 和 authorized.Use(MyMiddelware()) 表示只在authorized这个分组下的路由会经过MiddleWare()函数处理。
web服务通常是客户端和服务端交互,其中客户端向服务器发送请求,请求参数无非两种,查询字符串query string和报文体body参数。
query string参数指**?以后连接的key1=value2&key2=value2形式的参数,默认content-type是x-www-form-urlencoded**。Gin参数获取支持提供默认值,例如下面这段代码
func main(){
router := gin.Default()
router.GET("/welcome", func(c *gin.Context) {
firstname := c.DefaultQuery("firstname", "Guest")
lastname := c.Query("lastname")
c.String(http.StatusOK, "Hello %s %s", firstname, lastname)
})
router.Run()
}
HTTP报文体body传输格式常见的有以下4种
func main(){ router := gin.Default() router.POST("/form_post", func(c *gin.Context) { message := c.PostForm("message") nick := c.DefaultPostForm("nick", "anonymous") c.JSON(http.StatusOK, gin.H{ "status": gin.H{ "status_code": http.StatusOK, "status": "ok", }, "message": message, "nick": nick, }) }) }
常规的HTTP请求参数校验需要业务写大量的if else逻辑, Gin提供了参数bind功能支持参数校验。content-type无论是x-www-form-urlencoded 还是 **application/json **都支持。
type User struct { Username string `form:"username" json:"username" binding:"required"` Passwd string `form:"passwd" json:"passwd" bdinding:"required"` Age int `form:"age" json:"age"` } func main(){ router := gin.Default() router.POST("/login", func(c *gin.Context) { var user User var err error contentType := c.Request.Header.Get("Content-Type") switch contentType { case "application/json": err = c.BindJSON(&user) case "application/x-www-form-urlencoded": err = c.BindWith(&user, binding.Form) } if err != nil { fmt.Println(err) log.Fatal(err) } c.JSON(http.StatusOK, gin.H{ "user": user.Username, "passwd": user.Passwd, "age": user.Age, }) }) }
创建 Gin 实例
r := gin.Default() // 获取一个Gin的实例:Engine,gin的核心数据结构
这里获取了一个默认的 gin的实例
// Default returns an Engine instance with the Logger and Recovery middleware already attached. func Default() *Engine { debugPrintWARNINGDefault() engine := New() // 默认实例 engine.Use(Logger(), Recovery()) // 注册中间建,中间件的是一个函数,最终只要返回一个 type HandlerFunc func(*Context) 就可以 return engine } ```go #### 路由注册 ```go r.GET("/", func(c *gin.Context) { // 注册路由, 实际上是调用了 RouterGroup 的Get方法, RouterGroup 实现了 IRoutes interface,RouterGroup 主要提供路有注册功能 c.String(http.StatusOK, "Hello World!") }) // GET is a shortcut for router.Handle("GET", path, handle). func (group *RouterGroup) GET(relativePath string, handlers ...HandlerFunc) IRoutes { return group.handle(http.MethodGet, relativePath, handlers) } func (group *RouterGroup) handle(httpMethod, relativePath string, handlers HandlersChain) IRoutes { absolutePath := group.calculateAbsolutePath(relativePath) handlers = group.combineHandlers(handlers) // 注意这个 combineHandlers,这里会把 r.Use(gin.Logger(), gin.Recovery()) 注册的中间键跟业务的处理函数组合在一起 group.engine.addRoute(httpMethod, absolutePath, handlers) return group.returnObj() } func (group *RouterGroup) combineHandlers(handlers HandlersChain) HandlersChain { finalSize := len(group.Handlers) + len(handlers) if finalSize >= int(abortIndex) { panic("too many handlers") } mergedHandlers := make(HandlersChain, finalSize) copy(mergedHandlers, group.Handlers) // 中间键 copy(mergedHandlers[len(group.Handlers):], handlers) // 业务处理 return mergedHandlers } // IRoutes defines all router handle interface. type IRoutes interface { Use(...HandlerFunc) IRoutes Handle(string, string, ...HandlerFunc) IRoutes Any(string, ...HandlerFunc) IRoutes GET(string, ...HandlerFunc) IRoutes POST(string, ...HandlerFunc) IRoutes DELETE(string, ...HandlerFunc) IRoutes PATCH(string, ...HandlerFunc) IRoutes PUT(string, ...HandlerFunc) IRoutes OPTIONS(string, ...HandlerFunc) IRoutes HEAD(string, ...HandlerFunc) IRoutes // ... 省略代码 }
接收请求并响应
// ServeHTTP conforms to the http.Handler interface. func (engine *Engine) ServeHTTP(w http.ResponseWriter, req *http.Request) { c := engine.pool.Get().(*Context) c.writermem.reset(w) c.Request = req c.reset() engine.handleHTTPRequest(c) engine.pool.Put(c) } func (engine *Engine) handleHTTPRequest(c *Context) { // ... 省略代码 // Find root of the tree for the given HTTP method // x t := engine.trees for i, tl := 0, len(t); i < tl; i++ { if t[i].method != httpMethod { continue } root := t[i].root // Find route in tree value := root.getValue(rPath, c.params, unescape) if value.params != nil { c.Params = *value.params } // 找到处理的业务处理函数 if value.handlers != nil { c.handlers = value.handlers c.fullPath = value.fullPath c.Next() c.writermem.WriteHeaderNow() return } // ... 省略代码 } func (c *Context) Next() { c.index++ for c.index < int8(len(c.handlers)) { c.handlers[c.index](c) // 业务处理,也就是这里的 func HelloWorld(c *gin.Context), 也会跑中间键 c.index++ } } func HelloWorld(c *gin.Context) { c.String(http.StatusOK, "pong") }
前面我们提到只要一个结构体只要实现了 Handler 接口就可以提供HTTP 服务,gin实现了 Handler 接口 。所以它可以和原生的 http 包结合起来。整个流程就会变成如下图:
最底层的 net.Listener 在监听 TCP 段口,net库将接收到的请求给 http.Server , http.Server0最终会调用服务器实现的 ServerHTTP 函数,因为 gin 实现了 ServerHTTP 函数,所以最终处理请求会交给 gin 来处理。
参考地址:https://blog.csdn.net/chenguolinblog/article/details/90665140
https://blog.csdn.net/baidu_32452525/article/details/117003482
官方地址:https://github.com/gin-gonic/gin
详细文档地址:https://godoc.org/github.com/gin-gonic/gin
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。