在gin的框架中,中间件绑定在路由环节,常规的使用方式如下:
middlewares/auth.go
package middlewares
import (
"github.com/gin-gonic/gin"
"net/http"
)
func Auth() gin.HandlerFunc {
return func(c *gin.Context) {
token, _ := c.GetQuery("token")
if token == "" {
c.JSON(http.StatusForbidden, gin.H{"code":50008, "message":"非法访问!"})
c.Abort()
}
c.Next()
}
}
router.go
package routers
import (
"gin/controllers"
"gin/middlewares"
"github.com/gin-gonic/gin"
)
func InitRouter() *gin.Engine {
router := gin.Default()
router.Use(
middlewares.Cors(), //跨域中间件
middlewares.Auth(), //鉴权中间件
)
uploadGroup := router.Group("/upload")
{
uploadGroup.POST("/upload", controllers.Upload)
}
return router
}
=========================================================================
下面重点讲解下日志中间件,因为需要是从PHP转过来的老程序员,所以对PHP框架中的日志存储方式情有独钟,而gin原生的log是存储在一个文件内,很不习惯,因此,找到一个能够按照时间分割日志的包才安心。
1、将下面三个包拉到项目中
go get "github.com/lestrrat/go-file-rotatelogs"
go get "github.com/rifflock/lfshook"
go get "github.com/sirupsen/logrus"
2、中间件编写
package middlewares
import (
"fmt"
"github.com/gin-gonic/gin"
rotatelogs "github.com/lestrrat/go-file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"os"
"time"
)
func Logger() gin.HandlerFunc {
logClient := logrus.New()
//禁止logrus输出
src, err := os.OpenFile(os.DevNull, os.O_APPEND|os.O_WRONLY, os.ModeAppend)
if err != nil {
fmt.Println("err", err)
}
logClient.Out = src
logClient.SetLevel(logrus.DebugLevel)
apiLogPath := "logs/access.log"
logWriter, err := rotatelogs.New(
apiLogPath + ".%Y%m%d-%H%M.log",
rotatelogs.WithLinkName(apiLogPath), //生成软连接,指向新的日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), //文件最大保存时间
rotatelogs.WithRotationTime(24*time.Hour), //日志切割时间间隔
)
writeMap := lfshook.WriterMap{
logrus.InfoLevel: logWriter,
logrus.FatalLevel:logWriter,
}
lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{})
logClient.AddHook(lfHook)
return func(c *gin.Context) {
//开始时间
start := time.Now()
//执行逻辑
c.Next()
//结束时间
end := time.Now()
//执行时间
execTime := end.Sub(start)
path := c.Request.URL.Path //请求路径
clientIP := c.ClientIP() //请求IP
method := c.Request.Method //请求方式
statusCode := c.Writer.Status() //请求状态
logClient.Infof("|%3d | %13v | %15s | %s %s |",
statusCode,
execTime,
clientIP,
method,
path,
)
}
}
上图中,最不可忽略的当属 c.next() ,表示载入后续的逻辑代码执行,执行结束后继续此中间件的后续部分。
这个方式,让我想起了TP5中的钩子。
3、创建日志目录
在根目录创建logs,否则会因为路径不存在报错,当然加一个目录判断会是种不错的选择。
4、修改路由器
package routers
import (
"gin/controllers"
"gin/middlewares"
"github.com/gin-gonic/gin"
)
func InitRouter() *gin.Engine {
router := gin.Default()
router.Use(
middlewares.Cors(), //跨域中间件
middlewares.Auth(), //鉴权中间件
middlewares.Logger(), //日志中间件
)
uploadGroup := router.Group("/upload")
{
uploadGroup.POST("/upload", controllers.Upload)
}
return router
}