英文:
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))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论