Golang-web中间件入门指南
·
中间件
每个请求在到达你的核心处理逻辑之前,或者在响应发送给客户端之后,都会先经过这些中间件。
中间件的签名Signature
在Go的标准库 net/http 中,一个中间件本质上是一个函数,它接收一个 http.Handler 作为参数,并且返回一个新的 http.Handler。
听起来有点绕?别担心,我们把它拆开来看。
它的“类型签名”可以这样定义:
type Middleware func(http.Handler) http.Handler
让我们用一个具体的函数骨架来展示这个结构:
func MyMiddleware(next http.Handler) http.Handler {
// 我们返回一个新的Handler,通常用http.HandlerFunc来快速创建
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// ----------------------------------------------------
// 1. 在调用“下一个”Handler之前的逻辑
// 比如:记录请求开始、检查用户权限等
// ----------------------------------------------------
// 调用链中的下一个Handler(这可能是另一个中间件,也可能是最终的业务逻辑)
next.ServeHTTP(w, r)
// ----------------------------------------------------
// 2. 在调用“下一个”Handler之后的逻辑
// 比如:记录请求耗时、修改响应头等
// ----------------------------------------------------
})
}
代码实践
创建一个日志中间件,它能完成两件事:
- 在请求到达时,打印出请求的方法(GET, POST 等)和路径(URL)。
- 在请求处理完成后,计算并打印出整个请求花费了多长时间。
package main
import (
"fmt"
"log"
"net/http"
"time"
)
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("Incoming request: Method=%s, Path=%s", r.Method, r.URL.Path)
// 让下一个handler处理请求
next.ServeHTTP(w, r)
log.Printf("Request completed in %v", time.Since(start))
})
}
func helloHandler(w http.ResponseWriter, r *http.Request) {
// Simulate some work
time.Sleep(100 * time.Millisecond)
log.Printf("hello\n")
fmt.Fprintln(w, "Hello, Gopher!")
}
func main() {
finalHelloHandler := http.HandlerFunc(helloHandler)
http.Handle("/", loggingMiddleware(finalHelloHandler))
log.Println("Server starting on port 8080...")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
Gin的中间件
在Gin中,一个中间件就是一个 gin.HandlerFunc,它的签名是:
func(c *gin.Context)
c.Next()
它的作用就是告诉Gin:“我这个中间件的‘前置’任务做完了,现在请继续执行下一个中间件或者最终的业务处理函数”。
func Logger() gin.HandlerFunc {
return func(context *gin.Context) {
start := time.Now()
context.Next()
log.Printf("time :%v", time.Since(start))
}
}
func main() {
// 1. Create a Gin router
router := gin.Default()
// 2. Use our middleware globally
router.Use(Logger())
// 3. Define a route
router.GET("/test", func(c *gin.Context) {
// Simulate some work
time.Sleep(50 * time.Millisecond)
c.String(http.StatusOK, "Hello, Gin!")
})
// 4. Start the server
router.Run(":8080")
}

补充
- 状态码 (http.StatusOK):这就像是邮寄包裹时,在包裹外面盖的一个章,比如“已签收”或“地址错误”。它告诉接收方(浏览器)这个请求的结果是怎样的。
- 响应内容 (“Hello, Gin!”):这才是包裹里的东西,是用户真正想看到的内容。
所以,c.String(http.StatusOK, “Hello, Gin!”) 这行代码的完整意思是:“向浏览器发送一个状态为 200 OK 的成功响应,响应的内容是字符串Hello, Gin!
更多推荐



所有评论(0)