# 其他主题 基本上介绍完 `gin` 框架了,一个非常克制的框架,提供了路由、使用 `Context` 来封装数据。 golang的原生库对web开发是较为完善的,所有的框架只能是工具集。 ### 中间件 中间件实际上上特殊的 `HandleFuc` 注册在 `Engine.RouterGroup` 上,最终会附加到每个节点的handlerList前,每次处理时依次调用。 `gin` 提供了几个中间件: - auth: auth.go,完成基本的鉴权 - log: logger.go,完成请求日志输出 - recover: recover.go, 完成崩溃处理 ### 错误管理 错误管理是指在业务处理中可以将错误不断的设置到context中,然后可以一次性处理,比如记日志。 ``` // context.go:40 type Context struct { // 一系列的错误 Errors errorMsgs } Error(err error) *Error // 给本次请求添加个错误。将错误收集然后用中间件统一处理(打日志|入库)是一个比较好的方案 ``` ### 元数据管理 ``` // context.go:40 type Context struct { // 在context可以设置的值 Keys map[string]interface{} } Set(key string, value interface{}) //本次请求用户设置各种数据 (Keys 字段) Get(key string)(value interface{}, existed bool) MustGet(key string)(value interface{}) GetString(key string) string GetBool(key string) bool GetInt(key string) int GetInt64(key string) int64 GetFloat64(key string) float64 GetTime(key string) time.Time GetDuration(key string) time.Duration GetStringSlice(key string) []string GetStringMap(key string) map[string]interface{} GetStringMapString(key string) map[string]string GetStringMapStringSlice(key string) map[string][]string ``` ### 路由组 ``` import ( "net/http" "github.com/gin-gonic/gin" ) func main() { r := gin.New() // 使用日志插件 r.Use(gin.Logger()) r.GET("/", func(c *gin.Context) { c.String(http.StatusOK, "Hello world") }) // 使用路由组 authGroup := r.Group("/auth", func(c *gin.Context) { token := c.Query("token") if token != "123456" { c.AbortWithStatusJSON(200, map[string]string{ "code": "401", "msg": "auth fail", }) } c.Next() }) // 注册 /auth/info 处理者 authGroup.GET("/info", func(c *gin.Context) { c.JSON(200, map[string]string{ "id": "1234", "name": "name", }) }) r.Run("0.0.0:8910") } ``` 路由组可以将路由分组管理 ``` // routergroup.go:15 type IRouter interface { IRoutes Group(string, ...HandlerFunc) *RouterGroup } // routergroup.go:40 type RouterGroup struct { Handlers HandlersChain basePath string engine *Engine root bool } var _ IRouter = &RouterGroup{} // routergroup.go:55 func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { return &RouterGroup{ Handlers: group.combineHandlers(handlers), basePath: group.calculateAbsolutePath(relativePath), engine: group.engine, } } ``` 其实 `Engine` 就实现了 `IRouter` 接口 就是个 路由组;而路由组是基于路由组产生的。 ### 其他 我一直没有搞明白 `content negotiation` (context.go:750)是干嘛用的。