概念
- 一个完整的系统可能包括鉴权认证、权限管理、安全检查、日志记录等多维度的系统支持。
- 中间件位与服务器和实际业务处理程序之间,其含义就相当于在请求和具体的业务处理逻辑之间增加某些操作,这种以额外增加的方式不会影响编码的效率,也不会侵入到框架中。
中间件的位置和角色示意图
自定义一个中间件
- func函数
- 返回值是HandlerFunc类型
- 案例:定义一个log日志的中间件,打印path和Method
package main
import (
"fmt"
"github.com/gin-gonic/gin"
)
func main() {
router := gin.New()
// 全局使用自定义的中间件
router.Use(Logger())
router.GET("/hello", HelloHandle)
// 单个接口使用自定义的中间件
router.GET("/index", RemoteAddr(), IndexHandle)
router.Run(":8000")
}
func Logger() gin.HandlerFunc {
// 打印请求路径和方法的中间件
return func(ctx *gin.Context) {
fmt.Println(ctx.FullPath(), ctx.Request.Method)
}
}
func RemoteAddr() gin.HandlerFunc {
// 打印远程地址的中间件
return func(context *gin.Context) {
fmt.Println(context.Request.RemoteAddr)
}
}
func HelloHandle(ctx *gin.Context) {
ctx.Writer.Write([]byte("hello world!"))
}
func IndexHandle(ctx *gin.Context) {
ctx.Writer.Write([]byte("hello index!"))
}
context.Next函数
- contentx.Next函数可以将中间件代码的执行顺序一分为二,Next函数之前的代码在请求处理之前执行,当执行到Next函数时会中断向下执行,去执行具体的业务逻辑代码,当业务逻辑代码执行完成后,在继续执行Next函数后面的代码。
- 案例
package main
import (
"fmt"
"github.com/gin-gonic/gin"
"net/http"
)
func main() {
router := gin.Default()
// 全局使用自定义的中间件
router.Use(Logger())
router.GET("/hello", HelloHandle)
// 单个接口使用自定义的中间件
router.GET("/index", RemoteAddr(), IndexHandle)
router.Run(":8000")
}
func Logger() gin.HandlerFunc {
// 打印请求路径和方法的中间件
return func(ctx *gin.Context) {
fmt.Println(ctx.FullPath(), ctx.Request.Method)
fmt.Println("状态码", ctx.Writer.Status())
ctx.Next()
fmt.Println("状态码", ctx.Writer.Status())
}
}
func RemoteAddr() gin.HandlerFunc {
// 打印远程地址的中间件
return func(context *gin.Context) {
fmt.Println(context.Request.RemoteAddr)
// 中断执行,去执行接口业务代码,接口业务执行完毕后在回来执行context.Next()后面的代码
context.Next()
status := context.Writer.Status()
fmt.Println("状态码:", status)
}
}
func HelloHandle(ctx *gin.Context) {
ctx.String(http.StatusNotFound, "404 not found")
fmt.Println("hello接口执行完了")
}
func IndexHandle(ctx *gin.Context) {
fmt.Println("index函数执行了")
ctx.Writer.Write([]byte("hello index!"))
}