Go文档对http包有以下示例:
http.Handle("/foo", fooHandler)
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path))
})
我很难理解Handle和HandleFunc之间的区别以及为什么需要两个。有人可以用清楚的语言向新的Gopher解释吗?
答案 0 :(得分:37)
基本上,HTTP服务器的“mux”有一个路径映射 - >处理程序接口
我假设这里使用了接口,以允许您实现具有状态的复杂路径处理程序。
例如,标准包中的file server是一个包含文件服务根目录的结构,并实现了处理程序接口。
说,对于简单的东西,功能更简单,更清晰。所以他们添加了一个特殊的生成器,这样你就可以很容易地传入一个函数。
看看:server.go
从第1216行开始(截至今天)
1216 type HandlerFunc func(ResponseWriter, *Request)
1217
1218 // ServeHTTP calls f(w, r).
1219 func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
1220 f(w, r)
1221 }
他们正在做的是在自定义类型(恰好与接口的api匹配)上实现自己调用的接口。
答案 1 :(得分:6)
非常正确的答案,所以我不会多说,而是用简单的术语进行解释:
问题::我想创建一个响应HTTP请求的对象(类型)。
解决方案::使用http.Handle
,您创建的对象应从HTTP包中实现ServeHTTP
接口。
问题:我想要一个函数来响应我的HTTP请求。
解决方案:为此使用http.HandleFunc
并向HTTP服务器注册功能。
答案 2 :(得分:3)
否,与众不同。让我们检查一下
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
handle
希望我们通过Handler
。 Handler
是一个界面
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
例如,如果有任何type
实现了ServeHTTP(ResponseWriter, *Request)
:
myCustomHandler
,然后我们可以像Handle(pattern string, myCustomHandler)
一样传递它。
在第二种情况下:
HandleFunc(pattern string, func(w ResponseWriter, r *Request) {
// do some stuff
}
HandleFunc
需要一个函数,其中Handle
需要一个Handler
接口。
因此,如果您只想传递函数,则可以使用http.HandleFunc(..)
。就像@David一样,它在后台通过调用Handler
实现了ServeHTTP
接口。
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
答案 3 :(得分:0)
虽然它们都可以用来创建处理程序,但是因为使用处理程序函数更干净,而且它也能很好地完成工作,为什么要使用处理程序呢?这一切都归结为设计。如果您有一个现有的接口,或者如果您想要一个也可以用作处理程序的类型,只需向该接口添加一个 ServeHTTP 方法,您就会获得一个可以分配给 URL 的处理程序。它还可以让你 构建更加模块化的网络应用。
使用句柄
package main
import (
"fmt"
"net/http"
)
type HelloHandler struct{}
func (h *HelloHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
type WorldHandler struct{}
func (h *WorldHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
hello := HelloHandler{}
world := WorldHandler{}
http.Handle("/hello", &hello)
http.Handle("/world", &world)
http.ListenAndServe(":8080", nil)
}
使用 HandleFunc
package main
import (
"fmt"
"net/http"
)
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
func world(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "World!")
}
func main() {
http.HandleFunc("/hello", hello)
http.HandleFunc("/world", world)
http.ListenAndServe(":8080", nil)
}
附加信息:
http.Handler 是一个带有方法 ServeHTTP() 的接口,
// net/http/server.go
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
这里有一个 ServeHTTP 信息,
// net/http/server.go
ServeHTTP(w http.ResponseWriter, r *http.Request)
// where,
// http.ResponseWriter is a writer interface, and,
// http.Request is a structure with request details.
现在让我们看看 HandlerFunc,
// net/http/server.go
// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)
// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request){
f(w, r)
}
这意味着,http.HandlerFunc 是一个实现了 ServeHTTP 方法的类型。
http.HandlerFunc(someFunc)
// where,
// 1. someFunc() must have a signature,
func someFunc(w http.ResponseWriter, r *http.Request)
// 2. That means, http.HandlerFunc(someFunc) is just a type casting of type http.HandlerFunc on a someFunc() and not a function call.
现在让我们转到 http.Handle(),
// net/http/server.go
// Handle registers the handler for the given pattern
// in the DefaultServeMux.
// The documentation for ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) {
DefaultServeMux.Handle(pattern, handler)
}
通过查看上面的代码片段,您可能已经注意到, 第二个参数接受 Handler 接口,这意味着您可以创建任何类型并为其实现 ServeHTTP() 方法来满足这一点。参考下面的例子来证明。
type MyHandler struct{}
func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello World!")
}
func main() {
handler := MyHandler{}
http.Handle("/hello", &handler)
http.ListenAndServe()
}