http是go自带的web开发库,具有非常强大的web开发功能。本文以一个代码为例讲解请求的解析过程。
如下代码为例
- func main() {
- http.HandleFunc('/byte', sayByte)
- http.ListenAndServe(':8080', nil)
- }
- func sayByte(writer http.ResponseWriter, request *http.Request) {
- writer.Write([]byte(' say byte byte!!'))
- }
1. 路由注册
http.HandleFunc('/byte', sayByte)
1.1 此行代码会调用系统默认的ServeMux即DefaultServeMux,DefaultServeMux是http库定义的一个变量。
DefaultServeMux.HandleFunc(pattern, handler) // serve.go 2380行
1.2 并且利用HandlerFunc将函数sayByte转换成handler,
mux.Handle(pattern, HandlerFunc(handler)) // serve.go 2368行
1.3 真正向DefaultServeMux中注册路由和handler的是ServeMux的handle函数
- func (mux *ServeMux) Handle(pattern string, handler Handler) { // serve.go 2342
- mux.mu.Lock()
- defer mux.mu.Unlock()
- if pattern == '' {
- panic('http: invalid pattern')
- }
- if handler == nil {
- panic('http: nil handler')
- }
- if _, exist := mux.m[pattern]; exist {
- panic('http: multiple registrations for ' + pattern)
- }
- if mux.m == nil {
- mux.m = make(map[string]muxEntry)
- }
- mux.m[pattern] = muxEntry{h: handler, pattern: pattern}
- if pattern[0] != '/' {
- mux.hosts = true
- }
- }
1.4 查看ServeMux结构可知,路由和handler存储在ServeMux的m属性中,m是一个map
- type ServeMux struct { //serve.go 2133
- mu sync.RWMutex
- m map[string]muxEntry
- hosts bool // whether any patterns contain hostnames
- }
到此完成DefaultServeMux的初始化,也就是路由与handler的一一对应关系,存储在一个map中,键是路由,值是muxEntry,而由他存储路由与handler。
2.服务开启
http.ListenAndServe(':8080', nil)
2.1 监听端口
ln, err := net.Listen('tcp', addr) //serve.go 2707
2.2 接受请求
rw, e := l.Accept() //serve.go 2770
2.3 为请求创建一个连接
c := srv.newConn(rw) //serve.go 2793
2.4 开始服务
go c.serve(ctx) //serve.go 2795
2.5 初始化ServerHandler,并且调用他的ServeHTTP方法
serverHandler{c.server}.ServeHTTP(w, w.req) // serve.go //1830
2.6 ServeHttp方法会找出服务的一个ServeMux,如果没有用户自己没有初始化一个ServeMux,则会使用DefaultServeMux,也就是之前默认初始化的ServeMux,最后调用ServeMux的serveHTTP方法。
- func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { //serve.go 2686
- handler := sh.srv.Handler
- if handler == nil {
- handler = DefaultServeMux
- }
- if req.RequestURI == '*' && req.Method == 'OPTIONS' {
- handler = globalOptionsHandler{}
- }
- handler.ServeHTTP(rw, req)
- }
2.7 在ServeMux的serveHTTP方法中,找到处理函数并调用
- func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { //serve.go 2328
- if r.RequestURI == '*' {
- if r.ProtoAtLeast(1, 1) {
- w.Header().Set('Connection', 'close')
- }
- w.WriteHeader(StatusBadRequest)
- return
- }
- h, _ := mux.Handler(r) //根据url在ServeMux中的m属性中找到处理函数,
- h.ServeHTTP(w, r) //调用处理函数
- }
2.8 寻找处理函数的代码
- func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { /serve.go 2309
- mux.mu.RLock()
- defer mux.mu.RUnlock()
- // Host-specific pattern takes precedence over generic ones
- if mux.hosts {
- h, pattern = mux.match(host + path)
- }
- if h == nil {
- h, pattern = mux.match(path)
- }
- if h == nil {
- h, pattern = NotFoundHandler(), ''
- }
- return
- }
- func (mux *ServeMux) match(path string) (h Handler, pattern string) { // serve.go 2197
- // Check for exact match first.
- v, ok := mux.m[path]
- if ok {
- return v.h, v.pattern
- }
- // Check for longest valid match.
- var n = 0
- for k, v := range mux.m {
- if !pathMatch(k, path) {
- continue
- }
- if h == nil || len(k) > n {
- n = len(k)
- h = v.h
- pattern = v.pattern
- }
- }
- return
- }
注意:观察到ServeMux的m属性的值是muxEntry,结构如下
- type muxEntry struct { //serve.go 2139
- h Handler
- pattern string
- }
此处的handler是一个接口,在如下代码中,我们传入的是函数,最终由HandlerFunc将函数转成Handler。
http.HandleFunc('/byte', sayByte)
我们也可以直接实现Handler ,那么此时代码如下
- 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(':8080',nil)
- }
文章到此为止,介绍了
1.ServeMux的初始化过程
2.web请求处理过程
文中如果有错误还请严厉指出。