赞
踩
逻辑执行之前
逻辑执行之后
router := gin.New()
router.Use(gin.Logger())
router.Use(gin.Recovery())
注意:中间件的回调要先于用户定义的路径处理函数
中间件的使用顺序绝对了什么时候执行中间件,比如有三个路由:
router := gin.Default()
router.Get("/login",xxx)
router.Get("/user_list",xxx)
router.Get("/news_list",xxx)
加入user_list和news_list需要在登陆后才可以访问,login不要登录认证就可访问,
这时候我们需要一个token认证的中间件,那这个中间件Use的位置会有影响,如下:
router := gin.Default()
router.Get("/login",xxx)
router.User(MiddleWare())
router.Get("/user_list",xxx)
router.Get("/news_list",xxx)
Use不能放在login的前面,不然也会对login进行拦截认证
注意:Use不能放在login的前面,不然也会对login进行拦截认证
func MiddlewareA() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("MiddlewareA before request") // before request c.Next() // after request fmt.Println("MiddlewareA after request") } } func MiddlewareB() gin.HandlerFunc { return func(c *gin.Context) { fmt.Println("MiddlewareB before request") // before request c.Next() // after request fmt.Println("MiddlewareB after request") } }
//自定义中间件第1种定义方式 func MiddleWare1(ctx *gin.Context) { fmt.Println("这是自定义中间件1") } 自定义中间件第2种定义方式 func MiddleWare2() gin.HandlerFunc { return func(ctx *gin.Context) { fmt.Println("这是自定义i中间件2") } } router := gin.New() router.Use(MiddleWare1) // 需要加括号 router.Use(MiddleWare2()) // 不需要加括号,当成参数
在我们定义的众多中间件,会形成一条中间件链,而通过 Next 函数来对后面的中间件进行执行
特点:
func MiddleWare1(ctx *gin.Context) { fmt.Println("这是自定义中间件1--开始") ctx.Next() fmt.Println("这是自定义中间件1--结束") } func MiddleWare2() gin.HandlerFunc { return func(ctx *gin.Context) { fmt.Println("这是自定义中间件2--开始") if 3 < 4{ // 满足条件 ctx.Abort() } ctx.Next() fmt.Println("这是自定义中间件2--结束") } } func MiddleWare3(ctx *gin.Context) { fmt.Println("这是自定义中间件3--开始") ctx.Next() fmt.Println("这是自定义中间件3--结束") } router := gin.Default() router.Use(Middleware1,Middleware2(),Middleware3)
func Middle(ctx *gin.Context){
t := time.Now()
//可以设置一些公共参数
c.Set("example", "12345")
//等其他中间件先执行
c.Next()
//获取耗时
latency := time.Since(t)
fmt.Printf("cost time:%d us", latency/1000)
}
v1 := router.Group("/v1")
v1.Use(GroupRouterMiddle())
{
v1.Get...
}
绑定在根router上即可
router := gin.Default()
//使用自定义的全局中间件
router.Use(GlobalMiddle)
全局中间件 > 路由组中间件 > 路由中间件,如果是同一类别,那就取决于append的前后顺序了
func Middle1Ware() gin.HandlerFunc{
return func(c *gin.Context) {
t := time.Now()
fmt.Println("我是自定义中间件第2种定义方式---请求之前")
//在gin上下文中定义一个变量
c.Set("example", "CustomRouterMiddle2")
//请求之前
c.Next()
fmt.Println("我是自定义中间件第2种定义方式---请求之后")
//请求之后
//计算整个请求过程耗时
t2 := time.Since(t)
fmt.Println(t2)
}
}
// 路由映射时可以传多个HandlerFunc
router := gin.Default()
router.GET("/hello",Middle1Ware(),Hello)
// 局部使用中间价 chap05.GET("/basic",gin.BasicAuth(gin.Accounts{ "zs":"123456", "ls":"123", "ww":"1234", }),BasicAuthTest) // 私有数据 var map_data map[string]interface{} = map[string]interface{}{ "zs":gin.H{"age":18,"addr":"zs-xx"}, "ls":gin.H{"age":19,"addr":"ls-xx"}, "ww":gin.H{"age":20,"addr":"ww-xx"}, } // 获取私有数据。如果没有权限则获取不到 func BasicAuthTest(ctx *gin.Context) { user_name := ctx.Query("user_name") data ,ok := map_data[user_name] if ok{ ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":data}) }else { ctx.JSON(http.StatusOK,gin.H{"user_name":user_name,"data":"没有权限"}) } }
一文读懂HTTP Basic身份认证:https://juejin.im/entry/6844903586405564430
执行逻辑:
登录页面(没有中间件) – 会设置session – 其他路由回去session的key – 获取对应的数据
gin.WrapF(IndexHandler)
func IndexHandler(w http.ResponseWriter, r *http.Request) {
...
}
需要自己去定义struct实现这个Handler接口
type TestStruct struct {}
func (test *TestStruct) TestH(w http.ResponseWriter, r *http.Request) {
...
}
日志是程序的重要组成部分
1.什么是日志模板?
一种统一的格式,一种规范
2.日志模板的作用?
基于gin的日志中间件
// 1.创建日志文件
f, _ := os.Create("gin.log")
// 2.重新赋值DefaultWriter
gin.DefaultWriter = io.MultiWriter(f)
// 同时在控制台打印信息
gin.DefaultWriter = io.MultiWriter(f, os.Stdout)
LoggerWithFormatter中间件指定日志格式
router := gin.New() router.Use(gin.Recovery()) router.Use(gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { // 你的自定义格式 return fmt.Sprintf("%s\t|\t%s|\t%s|\t%s|\t%s|\t%d|\t%s|\t%s|\t%s \n", //客户端IP param.ClientIP, //时间格式 param.TimeStamp.Format("2006-01-02 15:04:05"), //http请求方式 get post等 param.Method, //客户端请求的路径 param.Path, //http请求协议版本 param.Request.Proto, //http请求状态码 param.StatusCode, //耗时 param.Latency, //http请求代理头 param.Request.UserAgent(), //处理请求错误时设置错误消息 param.ErrorMessage, ) }))
github.com/sirupsen/logrus
func LoggerFile(c *gin.Context) { file_dir := "logs/" + "gin_project.log" //写入文件 src, err := os.OpenFile(file_dir, os.O_APPEND|os.O_WRONLY, os.ModeAppend) if err != nil { fmt.Println("err", err) } //实例化 logger := logrus.New() //设置输出 logger.Out = src //设置日志级别 logger.SetLevel(logrus.DebugLevel) //设置日志格式,格式化时间 logger.SetFormatter(&logrus.TextFormatter{TimestampFormat:"2006-01-02 15:04:05"}) // 开始时间 startTime := time.Now() // 处理请求 c.Next() // 结束时间 endTime := time.Now() // 执行时间 latencyTime := endTime.Sub(startTime) // 请求方式 reqMethod := c.Request.Method // 请求路由 reqUri := c.Request.RequestURI // 状态码 statusCode := c.Writer.Status() // 请求IP clientIP := c.ClientIP() // 日志格式 logger.Infof("| %3d | %13v | %15s | %s | %s |", statusCode, latencyTime, clientIP, reqMethod, reqUri, ) }
router.Use(LoggerFile)
拆分:https://blog.csdn.net/u010918487/article/details/86146691
logrus 不支持输出文件名和行号
log_conf.json
{
"log_dir":"logs/gin_project.log",
"log_level":"info"
}
type LogConfig struct { LogDir string `json:"log_dir"` // 相对路径 + 文件名:e.g: logs/gin_project.log LogLevel string `json:"log_level"`// 日志級別 } func LoadLogConf() *LogConfig { log_conf := LogConfig{} file,err := os.Open("conf/log_conf.json") if err != nil { panic(err) } defer file.Close() byte_data,err2 := ioutil.ReadAll(file) if err2 != nil { panic(err2) } err3 := json.Unmarshal(byte_data,&log_conf) if err3 != nil { panic(err3) } return &log_conf }
package logs import ( "os" "github.com/sirupsen/logrus" ) var Log = logrus.New() // 创建一个log示例 func init() { // 日志級別映射 log_level_mapping := map[string]logrus.Level{ "trace":logrus.TraceLevel, "debug":logrus.DebugLevel, "info":logrus.InfoLevel, "warn":logrus.WarnLevel, "error":logrus.ErrorLevel, "fata":logrus.FatalLevel, "panic":logrus.PanicLevel, } // 初始化配置 log_conf := LoadLogConf() //设置输出 dir, err := os.OpenFile(log_conf.LogDir, os.O_APPEND|os.O_WRONLY, os.ModeAppend) if err != nil { fmt.Println("err", err) } Log.Out = dir // 设置日志级别 Log.Level = log_level_mapping[log_conf.LogLevel] //设置日志格式,格式化时间 Log.SetFormatter(&logrus.TextFormatter{TimestampFormat:"2006-01-02 15:04:05"}) } TextFormatter:文本格式 JSONFormatter:json格式
logs.Log.Warn("这是一个warnning级别的日志")
logs.Log.WithFields(logrus.Fields{
"msg": "测试的错误",
}).Warn("这是一个warnning级别的日志")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。