原文引用:
https://www.jianshu.com/p/be3d9cdc680b
https://www.jianshu.com/p/16210100d43d
hander函数: 具有
func(w http.ResponseWriter, r *http.Requests)
签名的函数(自定义的处理函数)handler处理器(函数): 经过
HandlerFunc
结构包装的handler函数
,它实现了ServeHTTP接口方法的函数。调用handler处理器的ServeHTTP方法时,即调用handler函数本身。handler对象:实现了Handler接口ServeHTTP方法的结构。
1、基本概念
mux: 多路复用器,也实现了ServeHTTP接口,是一个特殊的处理器,负责将请求转发给对应的路由处理器
Handle: 根据路径,注册一个处理器(是一个func来的)
HandleFunc: 处理器函数,对Handle进行一次封装,方便程序员调用(是一个func来的)
Handler: 是一个实现了ServerHTTP函数的接口
HandlerFunc: 是func(ResponseWriter, *Request)类型的一个别名
//任何实现http.Handler接口的对象都可作为一个处理器。
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
//HandlerFunc实现了Handler接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
//Handle 和 HandleFunc(是两个函数)
//源码剖析
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
if handler == nil {
panic("http: nil handler")
}
mux.Handle(pattern, HandlerFunc(handler))
}
//使用对比
mux.HandleFunc("/",helloworld)
mux.Handle("/",http.HandlerFunc(helloworld))//强制类型转换
经过HandlerFunc结构包装的handler函数,它实现了ServeHTTP接口方法的函数。
(ServeHTTP方法就是调用handler本身而已,本质上是handler)
调用handler处理器的ServeHTTP方法时,即调用handler函数本身。
//我们自己实现的func(ResponseWriter, *Request)函数没有实现Handler接口,所以要加上这一步转化
2、http包默认的server和mux
//http.HandleFunc调用的是,http包默认的mux
//由这个默认的mux去调用mux.Handle
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
3、创建新的server、mux
//使用http.Server 即可创建自定义的server对象:
//自定义的serverMux对象也可以传到server对象中。
mux := http.NewServeMux()
mux.HandleFunc("/",helloworld)
server := &http.Server{
Addr: ":8000",
ReadTimeout: 60 * time.Second,
WriteTimeout: 60 * time.Second,
Handler: mux,
}
server.ListenAndServe()
4、http工作流程
//源码
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
if r.RequestURI == "*" {
if r.ProtoAtLeast(1, 1) {
w.Header().Set("Connection", "close")
}
w.WriteHeader(StatusBadRequest)
return
}
h, _ := mux.Handler(r)
h.ServeHTTP(w, r)
}
//HandlerFunc实现了ServerHTTP接口
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
server底层一直监听着,当有新的请求来时,mux的ServeHTTP方法通过调用其Handler方法寻找注册到路由上的handler函数(就是自己写的HandleFunc),并调用该函数的ServeHTTP方法,即调用handler函数本身。
//---------------------------------------------------------------
mux的Handler方法对URL简单的处理,然后调用handler方法,后者会创建一个锁,同时调用match方法返回一个handler和pattern。
在match方法中,mux的m字段是map[string]muxEntry图,后者存储了pattern和handler处理器函数,因此通过迭代m寻找出注册路由的patten模式与实际url匹配的handler函数并返回。
返回的结构一直传递到mux的ServeHTTP方法,接下来调用handler函数的ServeHTTP方法,即helloworld函数,然后把response写到http.ResponseWriter对象返回给客户端。
上述函数运行结束即`serverHandler{c.server}.ServeHTTP(w, w.req)`运行结束。
接下来就是对请求处理完毕之后上希望和连接断开的相关逻辑。
至此,Golang中一个完整的http服务介绍完毕,包括注册路由,开启监听,处理连接,路由处理函数。
//-----------------------------------------------------------------
//总结
多数的web应用基于HTTP协议,客户端和服务器通过request-response的方式交互。一个server并不可少的两部分莫过于路由注册和连接处理。
Golang通过一个ServeMux实现了的multiplexer路由多路复用器来管理路由。
同时提供一个Handler接口提供ServeHTTP用来实现handler处理其函数,后者可以处理实际request并构造response。
ServeMux和handler处理器函数的连接桥梁就是Handler接口。
ServeMux的ServeHTTP方法实现了寻找注册路由的handler的函数,并调用该handler的ServeHTTP方法。
ServeHTTP方法就是真正处理请求和构造响应的地方。
回顾go的http包实现http服务的流程,可见大师们的编码设计之功力。
学习有利提高自身的代码逻辑组织能力。
更好的学习方式除了阅读,就是实践,接下来,我们将着重讨论来构建http服务。尤其是构建http中间件函数。
5、构造中间件Middleware
所谓中间件,就是连接上下级不同功能的函数或者软件,通常进行一些包裹函数的行为,为被包裹函数提供添加一些功能或行为。
go的http中间件很简单,只要实现一个函数签名为func(http.Handler) http.Handler的函数即可。http.Handler是一个接口,接口方法我们熟悉的为serveHTTP。返回也是一个handler。
//还是返回一个处理器,只不过该处理器被包装进了一些东西
func middlewareHandler(next http.Handler) http.Handler{
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
// 执行handler之前的逻辑
next.ServeHTTP(w, r)
// 执行完毕handler后的逻辑
})
}
//使用时,一层层的包裹进来即可
func main() {
http.Handle("/", loggingHandler(http.HandlerFunc(index)))
http.ListenAndServe(":8000", nil)
}
6、自定义mux
//任何结构体,只要实现了ServeHTTP方法,这个结构就可以称之为handler对象。ServeMux会使用handler并调用其ServeHTTP方法处理请求并返回响应。
//实现Handler接口
func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/" {
sayhelloName(w, r)
return
}
http.NotFound(w, r) //页面显示"404 page not found"
return
}
func sayhelloName(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello myroute!")
}
func main() {
mux := &MyMux{}
http.ListenAndServe(":9090", mux) //第二个参数就是Handler接口
}
//Go其实支持外部实现的路由器 ListenAndServe的第二个参数就是
//用以配置外部路由器的,它是一个Handler接口,即外部路由器只要实现了Handler接口就可以,我们可以在自己实现
//的路由器的ServHTTP里面实现自定义路由功能
有疑问加站长微信联系(非本文作者)