中间件基本概念
中间件(Middleware)是一种在HTTP请求到达最终处理程序(Handler)之前或之后执行特定功能的机制。
在 Go 语言里,net/http 是标准库中用于构建 HTTP 服务器的包,中间件则是处理 HTTP 请求时常用的技术。中间件其实就是一个函数,它会接收一个 http.Handler 类型的参数,并且返回另一个 http.Handler。中间件能够在请求到达最终处理程序之前或者响应返回客户端之前执行一些通用操作,像日志记录、认证、压缩等。
下面是一个简单的中间件函数示例:
go
go
package main
import (
"log"
"net/http"
)
// 中间件函数,接收一个 http.Handler 并返回另一个 http.Handler
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 在请求处理之前执行的操作
log.Printf("Received request: %s %s", r.Method, r.URL.Path)
// 调用下一个处理程序
next.ServeHTTP(w, r)
// 在请求处理之后执行的操作
log.Printf("Request completed: %s %s", r.Method, r.URL.Path)
})
}
// 最终处理程序
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
}
func main() {
// 创建一个新的 mux
mux := http.NewServeMux()
// 应用中间件到最终处理程序
mux.Handle("/", loggingMiddleware(http.HandlerFunc(helloHandler)))
// 启动服务器
log.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
- 中间件函数 loggingMiddleware:
- 它接收一个 http.Handler 类型的参数 next,代表下一个要执行的处理程序。
- 返回一个新的 http.HandlerFunc,在这个函数里可以执行请求处理前后的操作。
- next.ServeHTTP(w, r) 这行代码会调用下一个处理程序。
- 最终处理程序 helloHandler:
helloHandler是实际处理请求的函数,它会向客户端返回 "Hello, World!"。
中间件链式调用
多个中间件可以串联起来形成处理链:
go
package main
import (
"log"
"net/http"
)
// 日志中间件
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
log.Printf("Received request: %s %s", r.Method, r.URL.Path)
next.ServeHTTP(w, r)
log.Printf("Request completed: %s %s", r.Method, r.URL.Path)
})
}
// 认证中间件
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 简单的认证逻辑
authHeader := r.Header.Get("Authorization")
if authHeader != "Bearer secret_token" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
next.ServeHTTP(w, r)
})
}
// 最终处理程序
func helloHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, World!"))
}
func main() {
mux := http.NewServeMux()
// 应用多个中间件到最终处理程序
finalHandler := loggingMiddleware(authMiddleware(http.HandlerFunc(helloHandler)))
mux.Handle("/", finalHandler)
log.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", mux))
}
- 这里新增了一个 authMiddleware 中间件,用于简单的认证。
- 在 main 函数里,先把 authMiddleware 应用到 helloHandler 上,再把 loggingMiddleware 应用到结果上,这样就实现了多个中间件的组合。
通过使用中间件,能够让代码更具模块化和可维护性,并且可以在多个处理程序之间共享通用的逻辑。
中间件链中传递自定义参数
场景 :需要在多个中间件间共享数据(如请求ID、用户会话)
实现方式 :通过 context.Context
传递参数
go
package main
import (
"context"
"fmt"
"net/http"
)
// 中间件函数
func middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 设置上下文值
ctx := context.WithValue(r.Context(), "key", "value")
ctx = context.WithValue(ctx, "user_id", 123)
r = r.WithContext(ctx)
// 调用下一个处理函数
next.ServeHTTP(w, r)
})
}
// 处理函数
func handler(w http.ResponseWriter, r *http.Request) {
// 从上下文中获取值
value := r.Context().Value("key").(string)
userID := r.Context().Value("user_id").(int)
fmt.Fprintf(w, "Received user_id %d value: %v", userID, value)
}
func main() {
// 创建一个处理函数
mux := http.NewServeMux()
mux.HandleFunc("/", handler)
http.Handle("/", middleware(mux))
// 启动服务器
fmt.Println("Server started on :80")
http.ListenAndServe(":80", nil)
}
特点:
- 数据在中间件链中透明传递
- 避免全局变量和参数层层传递