上一小节对处理器进行了介绍,那么什么是处理器函数呢?处理器函数实际上就是与处理器拥有相同行为的函数:这些函数与ServeHTTP
方法拥有相同的签名,也就是说,它们接受ResponseWriter
和指向Request
结构的指针作为参数。代码清单3-8展示了如何在服务器中使用处理器函数。
代码清单3-8 使用处理器函数处理请求
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() {
server := http.Server {
Addr: "127.0.0.1:8080",
}
http.Handle("/hello", hello)
http.Handle("/world", world)
server.ListenAndServe()
}
处理器函数的实现原理是这样的:Go语言拥有一种HandlerFunc
函数类型,它可以把一个带有正确签名的函数f
转换成一个带有方法f
的Handler
。比如说,对下面这个hello
函数来说:
func hello(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello!")
}
程序只需要执行以下代码:
helloHandler := HandlerFunc(hello)
就可以把helloHandler
设置成一个Handler
。如果你对此感到疑惑,那么不妨回顾一下之前展示过的接受处理器的服务器代码
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{}
server := http.Server {
Addr: "127.0.0.1:8080",
}
http.Handle("/hello", &hello)
http.Handle("/world", &world)
server.ListenAndServe()
}
这个程序使用了以下这行代码来绑定URL地址/hello
和hello
函数:
http.Handle("/hello", &hello)
这行代码向我们展示了Handle
函数将一个处理器绑定至URL的具体方法。此外,在接受处理器函数的代码清单3-8中,HandleFunc
函数会将hello
函数转换成一个Handler
,并将它与DefaultServeMux
进行绑定,以此来简化创建并绑定Handler
的工作。换句话说,处理器函数只不过是创建处理器的一种便利的方法而已。代码清单3-9展示了http.HandleFunc
函数的具体定义。
代码清单3-9 http.HandleFunc
函数的源代码
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
//而下面是ServeMux.HandleFunc方法的定义:
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
注意这个方法是如何使用HandlerFunc
函数将传入的handler
函数转换成真正的处理器的。
虽然处理器函数能够完成跟处理器一样的工作,并且使用处理器函数的代码比使用处理器的代码更为整洁,但是处理器函数并不能完全代替处理器。这是因为在某些情况下,代码可能已经包含了某个接口或者某种类型,这时我们只需要为它们添加ServeHTTP方法就可以将它们转变为处理器了,并且这种转变也有助于构建出更为模块化的Web应用。