英文:
Declaring and assigning handlers to ServeMux in the loop does not work
问题
我有以下一段代码,但它的运行结果与预期不符。具体来说,所有对任何端点的请求都被处理为对/banana/auth
或/banana/description
端点的请求。
type Route struct {
AuthRoute string
DescriptionRoute string
}
var routes = [2]Route{
{
AuthRoute: "/apple/auth",
DescriptionRoute: "/apple/description",
},
{
AuthRoute: "/banana/auth",
DescriptionRoute: "/banana/description",
},
}
// ...
sm := http.NewServeMux()
for i, authServerConfig := range authServerConfigs {
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}
server := &http.Server{
// ...
Handler: sm,
// ...
}
server.ListenAndServe()
当我用下面的代码替换for循环后,它按照我期望的方式正常工作:
authHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[0].AuthRoute, authHandlerApple)
descriptionHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[0].DescriptionRoute, descriptionHandlerApple)
authHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[1].AuthRoute, authHandlerBanana)
descriptionHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[1].DescriptionRoute, descriptionHandlerBanana)
问题是,我最初做错了什么,如何避免编写第二个示例中的笨拙代码?
英文:
I have the following piece of code, and it doesn't work as expected. Specifically, all the requests to any endpoints are being handled as requests to either /banana/auth
or /banana/description
endpoints.
type Route struct {
AuthRoute string
DescriptionRoute string
}
var routes = [2]Route{
{
AuthRoute: "/apple/auth",
DescriptionRoute: "/apple/description",
},
{
AuthRoute: "/banana/auth",
DescriptionRoute: "/banana/description",
},
}
// ...
sm := http.NewServeMux()
for i, authServerConfig := range authServerConfigs {
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}
server := &http.Server{
// ...
Handler: sm,
// ...
}
server.ListenAndServe()
When I went ahead and replaced the for-loop with these statements, it worked exactly as I wanted:
authHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[0].AuthRoute, authHandlerApple)
descriptionHandlerApple := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[0].DescriptionRoute, descriptionHandlerApple)
authHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
}
sm.Handle(routes[1].AuthRoute, authHandlerBanana)
descriptionHandlerBanana := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
}
sm.Handle(routes[1].DescriptionRoute, descriptionHandlerBanana)
The question is, what was I originally doing wrong and how can I avoid writing a clunky code as in the second example?
答案1
得分: 2
根据FAQ - 闭包在作为goroutine运行时会发生什么的说明,每个闭包在for
循环中共享同一个变量authServerConfig
。要修复这个问题,只需在循环中添加authServerConfig := authServerConfig
。
for i, authServerConfig := range authServerConfigs {
authServerConfig := authServerConfig
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
})
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
})
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}
英文:
Per FAQ - What happens with closures running as goroutines, each closure shares that single variable authServerConfig
in the for
loop. To fix it, just add authServerConfig := authServerConfig
in the loop
for i, authServerConfig := range authServerConfigs {
authServerConfig := authServerConfig
authHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.Auth(w, r)
})
sm.Handle(routes[i].AuthRoute, authHandler)
descriptionHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authServerConfig.ServeDescription(w, r)
})
sm.Handle(routes[i].DescriptionRoute, descriptionHandler)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论