在Web开发中,中间件是无处不在的“幕后帮手”——它介于请求到达服务器和业务处理之间,默默处理日志记录、身份认证、请求限流等公共逻辑,让业务代码更聚焦核心功能。Go语言的net/http包天然支持中间件,且实现方式极其简洁。本文将从0到1,带你手写两个实用HTTP中间件,彻底理解Go中间件的核心原理。
一、Go中间件的核心:Handler接口
Go的HTTP处理围绕http.Handler接口展开,所有请求处理器都必须实现它:
type Handler interface {
ServeHTTP(w http.ResponseWriter, r *http.Request)
}
http.HandlerFunc是该接口的适配器,能把普通函数func(http.ResponseWriter, *http.Request)转换为Handler。而中间件的本质,就是一个接收http.Handler并返回新http.Handler的函数,签名通常为:
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 1. 请求前逻辑(如认证、日志)
next.ServeHTTP(w, r) // 2. 调用下一个处理器(业务逻辑)
// 3. 请求后逻辑(如耗时统计、响应处理)
})
}
二、第一个中间件:请求日志记录
日志是最常见的中间件需求,我们需要记录请求方法、路径、耗时等信息。
步骤1:写基础业务Handler
先实现一个简单的Hello接口:

import "fmt"
func helloHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, Go Middleware!")
}
步骤2:实现日志中间件
import (
"log"
"net/http"
"time"
)
func LogMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 请求前:记录开始时间
start := time.Now()
// 调用下一个处理器(业务逻辑)
next.ServeHTTP(w, r)
// 请求后:计算耗时并记录日志
duration := time.Since(start)
log.Printf("请求信息:method=%s, path=%s, 耗时=%v",
r.Method, r.URL.Path, duration)
})
}
步骤3:注册并运行服务
func main() {
// 用日志中间件包装业务Handler
http.Handle("/hello", LogMiddleware(http.HandlerFunc(helloHandler)))
log.Println("服务启动在: http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
运行后访问http://localhost:8080/hello,控制台会输出:
2024/05/20 10:00:00 请求信息:method=GET, path=/hello, 耗时=123.456µs
三、第二个中间件:简单身份认证
假设我们有一个受保护的接口,只有携带合法Token才能访问。
步骤1:实现认证中间件
func AuthMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 从请求头获取Token(格式:Bearer xxx)
token := r.Header.Get("Authorization")
// 简化验证:固定合法Token
if token != "Bearer valid-token-123" {
http.Error(w, "认证失败:无效Token", http.StatusUnauthorized)
return
}
// Token合法,继续调用下一个处理器
next.ServeHTTP(w, r)
})
}
步骤2:写受保护的业务Handler
func protectedHandler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "欢迎访问受保护接口!")
}
步骤3:串联多个中间件
中间件可以嵌套调用,顺序决定执行逻辑:
http.Handle("/protected",
AuthMiddleware(LogMiddleware(http.HandlerFunc(protectedHandler)))
)
执行顺序:
- 请求方向:
AuthMiddleware→LogMiddleware→protectedHandler - 响应方向:
protectedHandler→LogMiddleware→AuthMiddleware
测试:
- 无Token访问:返回
401 Unauthorized - 携带合法Token(Header加
Authorization: Bearer valid-token-123):正常返回,且日志记录请求
四、Go中间件的优势
- 解耦公共逻辑:日志、认证等与业务无关的代码抽离,业务Handler更专注核心功能;
- 高度复用:一个中间件可包装任意Handler,避免重复编码;
- 灵活串联:多个中间件可嵌套,顺序可按需调整(如先限流再认证);
- 零依赖:基于标准库实现,无需引入第三方框架,轻量高效。
总结
Go中间件的核心是http.Handler接口的灵活性,通过“接收Handler→返回新Handler”的模式,实现了公共逻辑的复用与解耦。掌握本文的日志和认证中间件后,你不仅能写出更简洁的Web服务,还能理解生态中(如gorilla/handlers、Echo框架)中间件的实现逻辑——这正是Go语言“简洁高效”的体现。
(全文约1050字)

发表评论