руководство по использованию джина (1)
руководство по использованию джина (2)
В последнем уроке в основном говорилось о маршрутизации и получении параметров gin, а в этой статье в основном рассказывается о промежуточном программном обеспечении gin.
Промежуточное ПО может выполнять некоторую обработку до или после обработки, когда мы получаем http-запрос. Обычно до хендла мы легко можем проверить через мидлвар, если после хендла, то можем внести какие-то коррективы в ответ.
Основное использование
использовать
// 创建一个不包含中间件的路由器
gin.New()
// 使用自定义中间件或者gin提供的中间件
gin.use(gin.Logger())
заменять
gin.Default()
На самом деле, gin по умолчанию использует ПО промежуточного слоя Logger и Recovery, а затем внутри себя вызывает New:
// gin.go
func Default() *Engine {
debugPrintWARNINGDefault()
engine := New()
engine.Use(Logger(), Recovery()) // 使用了Logger和Recovery两个中间件
return engine
}
Давайте кратко разберемся с этими двумя промежуточными программами:
- Промежуточное программное обеспечение Logger позволяет нам выполнять некоторые пользовательские настройки для печати.
- Промежуточное ПО для восстановления позволяет нам восстанавливаться после сбоев
func main() {
logfile, _ := os.Create("./logs/gin.log")
// 这里将log输出到指定文件
// 注意这个配置一定要在gin.Default()之前
gin.DefaultWriter = io.MultiWriter(logfile, os.Stdout)
router := gin.Default()
// 这里分别使用两个中间件
router.Use(gin.Logger())
router.Use(gin.Recovery())
router.POST("/test", func(context *gin.Context) {
var person Person
if err := context.ShouldBind(&person); err != nil {
context.JSON(http.StatusBadRequest, gin.H{
"error": err.Error(),
})
return
}
context.JSON(http.StatusOK, gin.H{
"success": true,
})
})
router.Run(":3000")
}
пользовательское промежуточное ПО
Чтобы реализовать промежуточное программное обеспечение самостоятельно, вы также можете взглянуть на то, как реализовано официально определенное промежуточное программное обеспечение восстановления.
// recovery.go
这里只要返回一个HandlerFunc类型即可
func Recovery() HandlerFunc {
return RecoveryWithWriter(DefaultErrorWriter)
}
// gin.go
HandlerFunc就是一个参数为*context的函数
type HandlerFunc func(*Context)
Поняв общую идею промежуточного программного обеспечения, мы можем вручную реализовать его самостоятельно.
Давайте напишем промежуточное программное обеспечение для проверки подлинности IP Предположим, что наше требование состоит в том, что только IP-адреса из белого списка могут получить доступ к серверу, тогда мы можем добиться этого:
// ipauth.go
func Auth() gin.HandlerFunc {
return func(context *gin.Context) {
// 定义ip白名单
whiteList := []string{
"127.0.0.1",
}
ip := context.ClientIP()
flag := false
for _, host := range whiteList {
if ip == host {
flag = true
break
}
}
if !flag {
context.String(http.StatusNetworkAuthenticationRequired, "your ip is not trusted: %s", ip)
context.Abort()
}
}
}
// main.go
func main() {
router := gin.New()
router.Use(ipauth.Auth())
router.GET("/test", func(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"success": true,
})
})
router.Run(":3000")
}
Пример теста:
// 如果你用localhost访问ip会显示为::1。
// 导致your ip is not trusted。这是因为你的电脑开启了ipv6支持,这是ipv6下的本地回环地址的表示。
$ curl http://127.0.0.1:3000/test
{"success":true}
// 把whiteList中的127.0.0.1改成127.0.0.2之后,我们再试一下
$ curl http://127.0.0.1:3000/test
your ip is not trusted: 127.0.0.1
Использовать промежуточное ПО в группе
Кроме того, наш middleware можно использовать не глобально, а только для части группы:
func main() {
router := gin.Default()
// 定义了group
authorized := router.Group("/auth", ipauth.Auth())
// 对上面这个group进行路由绑定
authorized.GET("/write", handle)
router.GET("/read", handle)
router.Run(":3000")
}
func handle(context *gin.Context) {
context.JSON(http.StatusOK, gin.H{
"success": true,
})
}
прецедент
$ curl http://127.0.0.1:3000/auth/write
your ip is not trusted: 127.0.0.1
$ curl http://127.0.0.1:3000/read
{"success":true}
Используйте промежуточное ПО для одного маршрута
Или только для одного маршрута:
func main() {
router := gin.Default()
// 注册一个路由,使用了 middleware1,middleware2 两个中间件
router.GET("/someGet", middleware1, middleware2, handler)
// 默认绑定 :8080
router.Run()
}
func handler(c *gin.Context) {
log.Println("exec handler")
}
func middleware1(c *gin.Context) {
log.Println("exec middleware1")
//你可以写一些逻辑代码
// 执行该中间件之后的逻辑
c.Next()
}
func middleware2(c *gin.Context) {
log.Println("arrive at middleware2")
// 执行该中间件之前,先跳到流程的下一个方法
c.Next()
// 流程中的其他逻辑已经执行完了
log.Println("exec middleware2")
//你可以写一些逻辑代码
}
Видно, что middleware пишется почти так же, как и обработчик маршрутизации, но вызывается чаще.c.Next()
. Eстьc.Next()
, мы можем контролировать изменение логики вызова в промежуточном программном обеспечении, см. код промежуточного программного обеспечения2 ниже. В промежуточном программном обеспечении2 выполните дляc.Next()
, Gin сразу перейдет к следующему методу процесса, и после выполнения этого метода вернется и выполнит оставшийся код промежуточного ПО2.
Поэтому запросите URL-адрес маршрута /someGet, зарегистрированный выше, запрос сначала достигает промежуточного ПО1, а затем достигает промежуточного ПО2, но в это время вызывается промежуточное ПО2.c.Next()
, поэтому код промежуточного ПО2 не выполняется, а переходит к обработчику.После выполнения обработчика он возвращается к промежуточному ПО2 и выполняет оставшийся код промежуточного ПО2.
Таким образом, мы можем увидеть следующий вывод журнала в консоли:
exec middleware1
arrive at middleware2
exec handler
exec middleware2
Использование горутин в промежуточном программном обеспечении
При запуске новой горутины в промежуточном программном обеспечении или обработчике не следует использовать в ней исходный контекст, необходимо использовать копию только для чтения (c.Copy()
)
func main() {
r := gin.Default()
r.GET("/long_async", func(c *gin.Context) {
// 创建要在goroutine中使用的副本
cCp := c.Copy()
go func() {
// simulate a long task with time.Sleep(). 5 seconds
time.Sleep(5 * time.Second)
// 这里使用你创建的副本
log.Println("Done! in path " + cCp.Request.URL.Path)
}()
})
r.Run(":3000")
}