英文:
How does middleware work in chi routing in Go and what does http.Handler argument refers to in middleware?
问题
-- routes.go --
package main
import (
"hotelsystem/pkg/config"
"hotelsystem/pkg/handlers"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func routes(app *config.AppConfig) http.Handler {
mux := chi.NewRouter()
mux.Use(middleware.Recoverer)
mux.Use(WriteToConsole)
mux.Get("/", handlers.Repo.Home)
mux.Get("/about", handlers.Repo.About)
return mux
}
-- middleware.go --
package main
import (
"fmt"
"net/http"
)
func WriteToConsole(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hit the page")
next.ServeHTTP(w, r)
})
}
-- main.go --
package main
import (
"hotelsystem/pkg/config"
"hotelsystem/pkg/handlers"
"hotelsystem/pkg/render"
"log"
"net/http"
)
const portNumber = ":3000"
func main() {
var app config.AppConfig
tc, err := render.CreateTemplateCache()
if err != nil {
log.Fatal("无法创建模板缓存", err)
}
app.TemplateCache = tc
app.UseCache = false
repo := handlers.NewRepo(&app)
handlers.NewHandlers(repo)
render.NewTemplate(&app)
// http.HandleFunc("/", handlers.Repo.Home)
// http.HandleFunc("/about", handlers.Repo.About)
// http.ListenAndServe(portNumber, nil)
srv := &http.Server{
Addr: portNumber,
Handler: routes(&app),
}
err = srv.ListenAndServe()
if err != nil {
log.Fatal(err)
}
}
我很难理解中间件。我正在使用 chi 进行路由。我不明白的是 WriteToConsole
函数中的 next http.Handler
参数是指什么?它是指我们的 mux 路由器吗?当我注释掉 WriteToConsole
函数中的 next.ServeHTTP
行时,HTML 就不会被渲染或其他任何操作。有人可以解释一下 next http.Handler
是指什么,以及 next.ServeHTTP
做了什么吗?
英文:
-- routes.go --
package main
import (
"hotelsystem/pkg/config"
"hotelsystem/pkg/handlers"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
)
func routes(app *config.AppConfig) http.Handler {
mux := chi.NewRouter()
mux.Use(middleware.Recoverer)
mux.Use(WriteToConsole)
mux.Get("/", handlers.Repo.Home)
mux.Get("/about", handlers.Repo.About)
return mux
}
-- middleware.go --
package main
import (
"fmt"
"net/http"
)
func WriteToConsole(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Hit the page")
next.ServeHTTP(w, r)
})
}
-- main.go --
package main
import (
"hotelsystem/pkg/config"
"hotelsystem/pkg/handlers"
"hotelsystem/pkg/render"
"log"
"net/http"
)
const portNumber = ":3000"
func main() {
var app config.AppConfig
tc, err := render.CreateTemplateCache()
if err != nil {
log.Fatal("Can't create templatecache", err)
}
app.TemplateCache = tc
app.UseCache = false
repo := handlers.NewRepo(&app)
handlers.NewHandlers(repo)
render.NewTemplate(&app)
// http.HandleFunc("/", handlers.Repo.Home)
// http.HandleFunc("/about", handlers.Repo.About)
// http.ListenAndServe(portNumber, nil)
srv := &http.Server{
Addr: portNumber,
Handler: routes(&app),
}
err = srv.ListenAndServe()
if err != nil {
log.Fatal(err)
}
}
I am having a hard time understanding the middleware.
I am using chi for routing.
What I didn't understand is what does that (next http.Handler
) argument in the WriteToConsole
refers to?
Does it refer to our mux router?
Also when I comment down the line next.ServeHTTP
of function writetoconsole the html is not rendered or anything? can someone explain me what does that next http.Handler
refers to and what next.serveHTTP
does?
答案1
得分: 8
next
是“处理程序链”中的下一个处理程序。
当你这样做:
mux.Use(middleware.Recoverer)
mux.Use(WriteToConsole)
mux.Get("/", handlers.Repo.Home)
mux.Get("/about", handlers.Repo.About)
实际上注册了两个“处理程序链”:
mux.Get("/", middleware.Recoverer(WriteToConsole(handlers.Repo.Home)))
mux.Get("/about", middleware.Recoverer(WriteToConsole(handlers.Repo.About)))
每个中间件函数返回的处理程序必须调用给定的next
处理程序,即执行next.ServeHTTP(w, r)
,如果不调用next
,则链条会中断,该链条中的其余处理程序将被忽略。
一个简化的代码示例可以更好地说明链式调用:
type handler func()
// 你的处理程序
func f() { fmt.Println("f") }
// 一个中间件
func g(next handler) handler {
return func() {
fmt.Print("g.")
next()
}
}
// 另一个中间件
func h(next handler) handler {
return func() {
fmt.Print("h.")
next()
}
}
有了上述代码,你可以这样做:
func main() {
h1 := h(g(f))
h1()
h2 := g(h(f))
h2()
// 你可以链式调用任意数量的这些中间件
// 以任意顺序。
h3 := h(g(h(h(h(g(g(h(f))))))))
h3()
}
https://play.golang.org/p/4NXquYsaljr
英文:
next
is the next handler in the "handler chain".
When you do:
mux.Use(middleware.Recoverer)
mux.Use(WriteToConsole)
mux.Get("/", handlers.Repo.Home)
mux.Get("/about", handlers.Repo.About)
You are essentially registering two "handler chains":
mux.Get("/", middleware.Recoverer(WriteToConsole(handlers.Repo.Home)))
mux.Get("/about", middleware.Recoverer(WriteToConsole(handlers.Repo.About)))
Each handler returned by the middleware function has to invoke the next
handler given to it, i.e. do next.ServeHTTP(w, r)
, if it doesn't invoke next
then the chain is broken and the rest of the handlers in that chain will be ignored.
A simplified code example may illustrate the chaining better:
type handler func()
// your handler
func f() { fmt.Println("f") }
// one middleware
func g(next handler) handler {
return func() {
fmt.Print("g.")
next()
}
}
// another middleware
func h(next handler) handler {
return func() {
fmt.Print("h.")
next()
}
}
With the above you can then do:
func main() {
h1 := h(g(f))
h1()
h2 := g(h(f))
h2()
// And you can chain as many of these as you like
// and in any order you like.
h3 := h(g(h(h(h(g(g(h(f))))))))
h3()
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论