# 其他主題
基本上介紹完 `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)是干嘛用的。