英文:
Go: use different handlers or inject variables into request Context?
问题
我有一个像这样的处理程序:
type handler struct {
Services *domain.Services
Config *domain.Config
}
然后,还有很多新的类型(可能有二十个或更多),像这样:
type Handler1 handler
type Handler2 handler
每个类型都有一个ServeHTTP
方法。我使用它们来访问Services和Config变量。
它们在路由中被使用,像这样:
r.Handle("/login", &h.Handler1{
Services: s,
Config: c,
})
我的问题是:我应该创建所有这些结构体,还是只创建一个函数将Services和Config注入请求上下文,然后我使用r.Context().Value()
来访问它们?
我考虑过这样做:
func handler1(w http.ResponseWriter, r *http.Request) {
s, c := r.Context().Value("services"), r.Context().Value("config")
// 我的代码
}
r.HandleFunc("/login", inject(handler1, s, c))
哪种方式是最好/推荐的?
英文:
I have an Handler like this:
type handler struct {
Services *domain.Services
Config *domain.Config
}
And then, a lot of new types (they can be twenty or more), like this:
type Handler1 handler
type Handler2 handler
And each one has a ServeHTTP
method. And I use this so they can access the Services and Config variables.
They are being used in routes like this:
r.Handle("/login", &h.Handler1{
Services: s,
Config: c,
})
My question is: should I create all of this structs or just create a function that injects the Services and Config into the request Context and then I access them using r.Context().Value()
?
I thought about doing this:
func handler1(w http.ResponseWriter, r *http.Request) {
s, c := r.Context().Value("services"), r.Context().Value("config")
// My code
}
r.HandleFunc("/login", inject(handler1, s, c))
What's the best/recommended?
答案1
得分: 2
作为创建所有这些处理程序类型的替代方案,您可以编写返回其他函数的函数(http.HandlerFunc)。这样,您将创建一个闭包,并且可以在处理程序中访问参数。例如:
package main
import (
"fmt"
"net/http"
)
func SomeHandler(conf SomeConfig, service SomeService) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "foobar config: %q", conf)
}
}
func main() {
// TODO: 初始化您的 conf 和 service
http.HandleFunc("/somepath", SomeHandler(conf, service))
}
以上代码示例中,SomeHandler
函数返回一个 http.HandlerFunc
类型的函数。这个返回的函数是一个闭包,可以访问 conf
和 service
参数。当请求到达处理程序时,闭包函数会将配置信息打印到响应中。您可以根据自己的需求进行修改和扩展。
英文:
As an alternative to creating all these handler types, you can have functions which return other functions (http.HandlerFunc). This way, you will create a closure and can access the parameters when the request arrives in the handler. For example:
<!-- language: lang-go -->
package main
import (
"fmt"
"net/http"
)
func SomeHandler(conf SomeConfig, service SomeService) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "foobar config: %q", conf)
}
}
func main() {
// TODO: initialise your conf & service
http.HandleFunc("/somepath", SomeHandler(conf, service))
}
答案2
得分: 0
你可能可以创建一种路由器,它提供ServeHTTP功能,并在真实处理程序和路由路径之间进行映射。
类似于这样的代码:
package main
import "net/http"
type Router struct {
routes map[string]func(rw http.ResponseWriter, r *http.Request)
}
func NewRouter() *Router {
var r Router
r.routes = make(map[string]func(rw http.ResponseWriter, r *http.Request))
return &r
}
func (router *Router) addRoute(path string, f func(rw http.ResponseWriter, r *http.Request)) {
router.routes[path] = f
}
func (router *Router) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
for route, serveHTTP := range router.routes {
if route == r.URL.Path {
serveHTTP(rw, r)
return
}
}
rw.WriteHeader(http.StatusNotFound)
}
func teapot(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusTeapot)
}
func ok(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
}
func main() {
r := NewRouter()
r.addRoute("/teapot", teapot)
r.addRoute("/ok", ok)
http.ListenAndServe("localhost:8080", r)
}
希望对你有帮助!
英文:
You probably could create some kind of Router which will provide ServeHTTP and do mapping between your real handlers and route paths.
Something like this:
package main
import "net/http"
type Router struct {
routes map[string]func(rw http.ResponseWriter, r *http.Request)
}
func NewRouter() *Router {
var r Router
r.routes = make(map[string]func(rw http.ResponseWriter, r *http.Request))
return &r
}
func (router *Router) addRoute(path string, f func(rw http.ResponseWriter, r *http.Request)) {
router.routes[path] = f
}
func (router *Router) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
for route, serveHTTP := range router.routes {
if route == r.URL.Path {
serveHTTP(rw, r)
return
}
}
rw.WriteHeader(http.StatusNotFound)
}
func teapot(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusTeapot)
}
func ok(rw http.ResponseWriter, r *http.Request) {
rw.WriteHeader(http.StatusOK)
}
func main() {
r := NewRouter()
r.addRoute("/teapot", teapot)
r.addRoute("/ok", ok)
http.ListenAndServe("localhost:8080", r)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论