Go语言封装web路由和中间件
Go语言里如何进行路由和封装中间件,进行业务和非业务逻辑的剥离呢?
包和导入
package main
import (
"log"
"net/http"
"time"
)
导入了三个包:
log
:用于日志记录。net/http
:用于处理 HTTP 请求和响应。time
:用于处理时间相关的操作。
处理函数
func welcome(wr http.ResponseWriter, r *http.Request) {
wr.Write([]byte("welcome"))
}
welcome
函数是一个简单的 HTTP 处理器函数,当访问/welcome
路由时,它会返回"welcome"
字符串作为响应。
中间件
func timeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {
timeStart := time.Now()
next.ServeHTTP(wr, r)
timeElapsed := time.Since(timeStart)
log.Println("time elapsed:", timeElapsed)
})
}
timeMiddleware
是一个记录请求处理时间的中间件。- 它接收一个
http.Handler
类型的参数next
,返回一个新的http.Handler
。 - 在处理请求前,记录开始时间
timeStart
。 - 调用
next.ServeHTTP
处理实际的请求。 - 记录处理结束时间,并计算耗时
timeElapsed
,然后记录日志。
自定义路由器
type Router struct {
middlewareChain []middleware
mux map[string]http.Handler
}
Router
结构体包含两个字段:middlewareChain
:存储中间件的切片。mux
:存储路由和相应处理器的映射。
type middleware func(http.Handler) http.Handler
- 定义了一个
middleware
类型,是一个函数类型,接收一个http.Handler
,返回一个http.Handler
。
func NewRouter() *Router {
return &Router{
mux: make(map[string]http.Handler),
}
}
NewRouter
函数创建并返回一个新的Router
实例。
func (r *Router) Use(m middleware) {
r.middlewareChain = append(r.middlewareChain, m)
}
Use
方法用于向路由器添加中间件。
func (r *Router) Add(route string, h http.Handler) {
var mergedHandler = h
for i := len(r.middlewareChain) - 1; i >= 0; i-- {
mergedHandler = r.middlewareChain[i](mergedHandler)
}
r.mux[route] = mergedHandler
}
Add
方法用于向路由器添加路由和相应的处理器。- 遍历中间件链,将每个中间件应用到处理器上。
func (r *Router) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
if handler, ok := r.mux[req.URL.Path]; ok {
handler.ServeHTTP(wr, req)
return
}
http.NotFound(wr, req)
}
ServeHTTP
方法使Router
结构体符合http.Handler
接口,用于处理传入的 HTTP 请求。- 根据请求路径查找相应的处理器,如果找到,则调用处理器的
ServeHTTP
方法。 - 如果没有找到相应的处理器,返回 404 错误。
主函数
func main() {
r := NewRouter()
r.Use(timeMiddleware)
r.Add("/welcome", http.HandlerFunc(welcome))
http.Handle("/", r)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
- 在
main
函数中:- 创建一个新的
Router
实例r
。 - 添加
timeMiddleware
中间件。 - 添加
/welcome
路由,并将其处理器设置为welcome
函数。 - 将自定义路由器
r
注册到 HTTP 服务器根路径/
。 - 启动 HTTP 服务器,监听端口
8080
。
- 创建一个新的
通过这种方式,你可以使用自定义的路由器处理 HTTP 请求,并在处理请求的过程中应用中间件。例如,当访问 /welcome
路由时,请求会先经过 timeMiddleware
记录处理时间,然后再由 welcome
处理器处理请求。
完整代码
package main
import (
"log"
"net/http"
"time"
)
func welcome(wr http.ResponseWriter, r *http.Request) {
wr.Write([]byte("welcome"))
}
// timeMiddleware 记录请求处理时间的中间件
func timeMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(wr http.ResponseWriter, r *http.Request) {
timeStart := time.Now()
next.ServeHTTP(wr, r)
timeElapsed := time.Since(timeStart)
log.Println("time elapsed:", timeElapsed)
})
}
type Router struct {
middlewareChain []middleware
mux map[string]http.Handler
}
type middleware func(http.Handler) http.Handler
func NewRouter() *Router {
return &Router{
mux: make(map[string]http.Handler),
}
}
func (r *Router) Use(m middleware) {
r.middlewareChain = append(r.middlewareChain, m)
}
func (r *Router) Add(route string, h http.Handler) {
var mergedHandler = h
for i := len(r.middlewareChain) - 1; i >= 0; i-- {
mergedHandler = r.middlewareChain[i](mergedHandler)
}
r.mux[route] = mergedHandler
}
// ServeHTTP 方法使 Router 结构体符合 http.Handler 接口,用于处理传入的 HTTP 请求。
func (r *Router) ServeHTTP(wr http.ResponseWriter, req *http.Request) {
if handler, ok := r.mux[req.URL.Path]; ok {
handler.ServeHTTP(wr, req)
return
}
http.NotFound(wr, req)
}
func main() {
r := NewRouter()
r.Use(timeMiddleware)
r.Add("/welcome", http.HandlerFunc(welcome))
http.Handle("/", r)
err := http.ListenAndServe(":8080", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}