为何Go程序中midd()启动时执行而非访问/p3时执行?
Go中间件执行时机问题解答
问题现象
程序启动时终端立刻打印hello,访问localhost:5000/p1打印called 1、访问/p2打印called 2,但访问/p3时仅打印called 3,不会打印hello。疑惑为何midd()会在程序启动时被调用,而非访问/p3时才执行。
原代码
package main import ( "fmt" "log" "net/http" ) func main() { runserver() } func runserver() { err := http.ListenAndServe(":5000", mux()) if err != nil { log.Fatal(err) } } func mux() *http.ServeMux { mux := http.NewServeMux() mux.HandleFunc("/p1", func1) mux.HandleFunc("/p2", func2) mux.HandleFunc("/p3", midd("hello", func3)) return mux } func func1(w http.ResponseWriter, r *http.Request) { fmt.Println("called 1") w.Write([]byte("hello from 1")) } func func2(w http.ResponseWriter, r *http.Request) { fmt.Println("called 2") w.Write([]byte("hello from 2")) } func func3(w http.ResponseWriter, r *http.Request) { fmt.Println("called 3") w.Write([]byte("hello from 3")) } func midd(random string, hfunc http.HandlerFunc) http.HandlerFunc { fmt.Println(random) return hfunc }
原因分析
在mux()函数初始化路由时,midd("hello", func3)是直接执行函数调用,不是把midd作为参数传递。程序启动时mux()会被执行,此时midd()就会立刻运行,打印hello,然后将返回的func3注册给/p3路由。当后续访问/p3时,实际执行的是func3,midd()早已在启动阶段执行完毕,所以不会再打印hello。
正确的中间件写法
中间件需要返回一个新的匿名HandlerFunc,将中间件逻辑放在这个匿名函数内部,这样每次请求触发时才会执行中间件代码:
func midd(random string, hfunc http.HandlerFunc) http.HandlerFunc { // 这里的代码仍会在启动时执行(如果有需要) return func(w http.ResponseWriter, r *http.Request) { // 以下代码会在每次请求/p3时执行 fmt.Println(random) // 调用原handler hfunc(w, r) } }
修改后,启动时midd()仅返回匿名函数,不会执行中间件的打印逻辑;当访问/p3时,匿名函数被调用,先打印hello,再执行func3,符合预期。
内容的提问来源于stack exchange,提问作者Antubus
相关产品推荐
相关产品推荐

