Go: use different handlers or inject variables into request Context?

huangapple go评论133阅读模式
英文:

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 类型的函数。这个返回的函数是一个闭包,可以访问 confservice 参数。当请求到达处理程序时,闭包函数会将配置信息打印到响应中。您可以根据自己的需求进行修改和扩展。

英文:

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 (
    &quot;fmt&quot;
    &quot;net/http&quot;
)

func SomeHandler(conf SomeConfig, service SomeService) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, &quot;foobar config: %q&quot;, conf)
    }
}

func main() {
    // TODO: initialise your conf &amp; service
    http.HandleFunc(&quot;/somepath&quot;, 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 &quot;net/http&quot;

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 &amp;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(&quot;/teapot&quot;, teapot)
	r.addRoute(&quot;/ok&quot;, ok)

	http.ListenAndServe(&quot;localhost:8080&quot;, r)
}

huangapple
  • 本文由 发表于 2016年11月15日 07:48:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/40599775.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定