Объявление и назначение обработчиков ServeMux в цикле не работает

У меня есть следующий фрагмент кода, и он не работает должным образом. В частности, все запросы к любым конечным точкам обрабатываются как запросы к/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)

Вопрос в том, что я изначально делал не так и как мне избежать написания корявого кода, как во втором примере?

1 ответ

Согласно часто задаваемым вопросам - что происходит с замыканиями, работающими как горутины , каждое замыкание использует эту единственную переменную.authServerConfig вforпетля. Чтобы исправить это, просто добавьте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)
}
Другие вопросы по тегам