当前位置:   article > 正文

Gin项目实战07-middleware(接口设置超时时间)及原理剖析_gin 实战

gin 实战

本篇博客从 接口超时middleware 的案例入手 深入剖析其原理

1、接口超时中间件

在项目根目录创建middleware 目录,然后在middleware目录创建time_out.go,代码如下

package middleware

import (
	"github.com/gin-gonic/gin"
	"golang.org/x/net/context"
	"net/http"
	"time"
)

// TimeoutMiddleware 是一个用于设置超时时间的中间件
func TimeoutMiddleware(timeout time.Duration) gin.HandlerFunc {
	return func(c *gin.Context) {
		ctx, cancel := context.WithTimeout(c.Request.Context(), timeout)
		defer cancel()

		c.Request = c.Request.WithContext(ctx)

		response := make(chan bool, 1)

		go func() {
			c.Next()
			response <- true
		}()

		select {
		case <-response:
			return
		case <-ctx.Done():
			if ctx.Err() == context.DeadlineExceeded {
				c.JSON(http.StatusRequestTimeout, gin.H{"message": "Request timeout"})
				c.Abort()
				return
			}
		}
	}
}

  • 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

然后更改/router/router.go代码,完整代码如下

package router

import (
	"ginWeb/handler"
	"ginWeb/middleware"
	"github.com/gin-gonic/gin"
	"time"
)

func InitRoutes(app *handler.App) *gin.Engine {
	router := gin.New()
	root := router.Group("/gin-web")
	v1 := root.Group("v1")
	v1.Use(middleware.TimeoutMiddleware(time.Second * 5))
	uaa := &uaa{app.Uaa}
	uaa.addRouter(v1)
	return router
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

为了测试timeout 中间件是否有效,我们在login 接口 睡眠6s,/handler/uaa.go 完整代码如下

package handler

import (
	log "ginWeb/common/logger"
	"time"

	"golang.org/x/net/context"
)

type UaaHandler interface {
	Login(ctx context.Context, req *LoginReq, rsp *LoginRsp) error
}

type uaa struct {
}

func newUaaHandler() UaaHandler {
	return &uaa{}
}

type LoginReq struct{}

type LoginRsp struct {
	Id   string `json:"id"`
	Name string `json:"name"`
}

func (u *uaa) Login(ctx context.Context, req *LoginReq, rsp *LoginRsp) error {
	log.Error("===========login==========start", nil)
	rsp.Id, rsp.Name = "1", "小明"
	time.Sleep(6 * time.Second)
	log.Error("===========login==========end", nil)
	return nil
}

  • 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

然后启动项目 打开终端在项目根目录 执行 go run main.go
执行 curl -XPOST http://127.0.0.1:8090/gin-web/v1/uaa/login ,会出现下面结果

{"message":"Request timeout"}
  • 1

2、middleware 原理剖析

中间件的方法只需要定义为 func() gin.HandlerFunc {} 或
func(p inteface) gin.HandlerFunc {},方法的返回值 只能是 gin.HandlerFunc

看下面源码实现

type RouterGroup struct {
	Handlers HandlersChain
	basePath string
	engine   *Engine
	root     bool
}
type HandlersChain []HandlerFunc
var _ IRouter = (*RouterGroup)(nil)

// Use adds middleware to the group, see example code in GitHub.
func (group *RouterGroup) Use(middleware ...HandlerFunc) IRoutes {
	group.Handlers = append(group.Handlers, middleware...)
	return group.returnObj()
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

RouterGroup 结构体包括 Handlers 字段,该字段 为 HandlerFunc 切片 类型,和 中间件定义返回值相关,

*func (group RouterGroup) Use(middleware …HandlerFunc) IRoutes{} 方法 把 中间件定义的 返回值 追加到 Handlers 里边,因为是切片 所以这 一系列的中间件也是按照 Use 的顺序进行调用的。后续还有log、限流、auth等中间件讲解,下一篇博客我们使用gorm进行数据读写操作

创作不易,喜欢的话请一键三连,转载请注明出处,侵权必究

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/624891
推荐阅读
相关标签
  

闽ICP备14008679号