为每个处理程序添加响应头,而无需重复相同的行。

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

Add response header to every handler without repeating the same line

问题

我正在编写一个小型网站,对于每个页面,我都在其头部添加一个服务器名称:

func httpSignUp(rw http.ResponseWriter, req *http.Request) {
    rw.Header().Set("Server", SERVER_NAME)
}

我想知道是否有一种方法可以设置http.ResponseWriter的默认服务器名称,这样我就不必一遍又一遍地使用相同的代码了。

英文:

I am writing a small website and for every page, I am putting a server name to its header:

func httpSignUp(rw http.ResponseWriter, req *http.Request) {
	rw.Header().Set("Server", SERVER_NAME)
}

I am wondering if there's a way that I can set http.ResponseWriter's default server name, so I don't have to use the same line over and over?

答案1

得分: 10

创建一个包装器来设置头部:

func wrap(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", SERVER_NAME)
        h.ServeHTTP(w, r)
    })
}

包装单个处理程序:

http.Handle("/path", wrap(aHandler))
http.Handle("/another/path", wrap(anotherHandler))

或者将根处理程序传递给ListenAndServe:

log.Fatal(http.ListenAndServe(addr, wrap(rootHandler)))
英文:

Create a wrapper to set the header:

func wrap(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) (
         w.Header().Set("Server", SERVER_NAME)
         h.ServeHTTP(w, r)
    })
}

Wrap individual handlers

http.Handle("/path", wrap(aHandler)(
http.Handle("/another/path", wrap(anotherHandler))

or the root handler passed to ListenAndServe:

log.Fatal(http.ListenAndServe(addr, wrap(rootHandler))

答案2

得分: 3

“优先使用组合而不是继承”-《设计模式》

首先,Golang本身并没有设计继承的概念。如果你对为什么这样设计有详细的解释,我相信在Stack Overflow上已经有人回答了,所以我会直接给你一个链接:https://stackoverflow.com/questions/1727250/embedding-instead-of-inheritance-in-go。

实际上,你可以通过适配器设计模式来实现相同的结果,它可以让你扩展内置库的功能,对我来说,它比继承更加灵活。

func adapter(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Server", SERVER_NAME)
    h.ServeHTTP(w, r)
  })
}

或者将serverName作为参数传入:

func adapter(h http.Handler, serverName string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Server", serverName)
    h.ServeHTTP(w, r)
  })
}

最后,你可以灵活选择要“继承”的处理程序:

http.Handle("/path", adapter(your_handler))

如果是针对所有处理程序,只需将其“继承”到根处理程序:

http.ListenAndServe(port, adapter(root_Handler))
英文:

>"Prefer composition to inheritance" - Gang of 4

Inheritance simply wasn't designed into Golang in the first place. 为每个处理程序添加响应头,而无需重复相同的行。

If you are looking for detailed explanations on the why part, I believed this has been answered on SO, hence I would just point you to it: https://stackoverflow.com/questions/1727250/embedding-instead-of-inheritance-in-go.

Well, you can actually achieve the same result with adapter design pattern, which enables you to extend functionality from a built-in library, and to me, its way more flexible than inheritance.

func adapter(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", SERVER_NAME)
    h.ServeHTTP(w, r)
  })
}

Or pass in serverName as parameter:

func adapter(h http.Handler, serverName string) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Server", serverName)
    h.ServeHTTP(w, r)
  })
}

Finally, you have the flexibility to choose which handler(s) to be 'inherited':

http.Handle("/path", adapter(your_handler))

Or if its meant for every handlers, just 'inherit' to the root-handler:

http.ListenAndServe(port, adapter(root_Handler))

答案3

得分: 3

http.ResponseWriter 是一个接口(interface),而不是一个结构体(struct)。因此,你不能直接扩展它。你需要扩展内部的结构体。但这不是解决这个问题的惯用方式。

你可以采用一种方法,即使用中间件(middleware)。中间件只是一段在主请求处理程序之前执行的代码,可以用于执行一些常见任务。

例如,使用中间件的方式来编写相同的代码:

func injectServerHeader(handler http.Handler, serverName string) http.Handler {
    ourFunc := func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", serverName)
        handler.ServeHTTP(w, r)
    }
    return http.HandlerFunc(ourFunc)
}

这样,你将实际的 HTTP 处理程序包装在中间件中。这样,你就不必一遍又一遍地编写相同的代码。

例如:

http.Handle("/some-path", injectServerHeader(aHandler))
英文:

The http.ResponseWriter is an interface, not a struct. So, You cannot extend it directly. You need to extend the internal struct. But it is not idiomatic way to solve this problem.

One approach you can take is to use middleware. middleware is just a piece of code which will be executed before your main request handler, and can be used perform some common tasks.

For example, to write the same thing using middleware approach:

func injectServerHeader(handler http.Handler, serverName string) http.Handler {
    ourFunc := func(w http.ResponseWriter, r *http.Request) {
        w.Header().Set("Server", serverName)
        handler.ServeHTTP(w, r)
    }
    return http.HandlerFunc(ourFunc)
}

This way, you wrap your actual http handler with middleware. So, you won't have to write same code over and over again.

For example:

http.Handle("/some-path", injectServerHeader(aHandler))

huangapple
  • 本文由 发表于 2016年4月8日 09:49:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/36490162.html
匿名

发表评论

匿名网友

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

确定