Golang:net/http包深入理解

HarperNigel 发布于2月前
0 条问题

原文引用:

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里面实现自定义路由功能

查看原文: Golang:net/http包深入理解

  • tinymeercat
  • blackfrog
  • yellowbear
  • ticklishpanda
  • redbear
  • ticklishtiger
  • organicgorilla
  • heavymeercat
需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。