diff --git a/zh/03.4.md b/zh/03.4.md index a76b9a01..592b0622 100644 --- a/zh/03.4.md +++ b/zh/03.4.md @@ -9,11 +9,11 @@ Go的http有两个核心功能:Conn、ServeMux Go在等待客户端请求里面是这样写的: ```Go - c, err := srv.newConn(rw) - if err != nil { - continue - } - go c.serve() +c, err := srv.newConn(rw) +if err != nil { + continue +} +go c.serve() ``` 这里我们可以看到客户端的每次请求都会创建一个Conn,这个Conn里面保存了该次请求的信息,然后再传递到对应的handler,该handler中便可以读取到相应的header信息,这样保证了每个请求的独立性。 @@ -24,85 +24,85 @@ Go在等待客户端请求里面是这样写的: 它的结构如下: ```Go - type ServeMux struct { - mu sync.RWMutex //锁,由于请求涉及到并发处理,因此这里需要一个锁机制 - m map[string]muxEntry // 路由规则,一个string对应一个mux实体,这里的string就是注册的路由表达式 - hosts bool // 是否在任意的规则中带有host信息 - } +type ServeMux struct { + mu sync.RWMutex //锁,由于请求涉及到并发处理,因此这里需要一个锁机制 + m map[string]muxEntry // 路由规则,一个string对应一个mux实体,这里的string就是注册的路由表达式 + hosts bool // 是否在任意的规则中带有host信息 +} ``` 下面看一下muxEntry ```Go - type muxEntry struct { - explicit bool // 是否精确匹配 - h Handler // 这个路由表达式对应哪个handler - pattern string //匹配字符串 - } +type muxEntry struct { + explicit bool // 是否精确匹配 + h Handler // 这个路由表达式对应哪个handler + pattern string //匹配字符串 +} ``` 接着看一下Handler的定义 ```Go - type Handler interface { - ServeHTTP(ResponseWriter, *Request) // 路由实现器 - } +type Handler interface { + ServeHTTP(ResponseWriter, *Request) // 路由实现器 +} ``` Handler是一个接口,但是前一小节中的`sayhelloName`函数并没有实现ServeHTTP这个接口,为什么能添加呢?原来在http包里面还定义了一个类型`HandlerFunc`,我们定义的函数`sayhelloName`就是这个HandlerFunc调用之后的结果,这个类型默认就实现了ServeHTTP这个接口,即我们调用了HandlerFunc(f),强制类型转换f成为HandlerFunc类型,这样f就拥有了ServeHTTP方法。 ```Go - type HandlerFunc func(ResponseWriter, *Request) +type HandlerFunc func(ResponseWriter, *Request) - // ServeHTTP calls f(w, r). - func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { - f(w, r) - } +// ServeHTTP calls f(w, r). +func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { + f(w, r) +} ``` 路由器里面存储好了相应的路由规则之后,那么具体的请求又是怎么分发的呢?请看下面的代码,默认的路由器实现了`ServeHTTP`: ```Go - func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { - if r.RequestURI == "*" { - w.Header().Set("Connection", "close") - w.WriteHeader(StatusBadRequest) - return - } - h, _ := mux.Handler(r) - h.ServeHTTP(w, r) +func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { + if r.RequestURI == "*" { + w.Header().Set("Connection", "close") + w.WriteHeader(StatusBadRequest) + return } + h, _ := mux.Handler(r) + h.ServeHTTP(w, r) +} ``` 如上所示路由器接收到请求之后,如果是`*`那么关闭链接,不然调用`mux.Handler(r)`返回对应设置路由的处理Handler,然后执行`h.ServeHTTP(w, r)` 也就是调用对应路由的handler的ServerHTTP接口,那么mux.Handler(r)怎么处理的呢? ```Go - func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { - if r.Method != "CONNECT" { - if p := cleanPath(r.URL.Path); p != r.URL.Path { - _, pattern = mux.handler(r.Host, p) - return RedirectHandler(p, StatusMovedPermanently), pattern - } - } - return mux.handler(r.Host, r.URL.Path) +func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { + if r.Method != "CONNECT" { + if p := cleanPath(r.URL.Path); p != r.URL.Path { + _, pattern = mux.handler(r.Host, p) + return RedirectHandler(p, StatusMovedPermanently), pattern + } + } + return mux.handler(r.Host, r.URL.Path) +} + +func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { + mux.mu.RLock() + defer mux.mu.RUnlock() + + // Host-specific pattern takes precedence over generic ones + if mux.hosts { + h, pattern = mux.match(host + path) } - - func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { - 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 + if h == nil { + h, pattern = mux.match(path) } + if h == nil { + h, pattern = NotFoundHandler(), "" + } + return +} ``` 原来他是根据用户请求的URL和路由器里面存储的map去匹配的,当匹配到之后返回存储的handler,调用这个handler的ServeHTTP接口就可以执行到相应的函数了。 @@ -111,33 +111,33 @@ Handler是一个接口,但是前一小节中的`sayhelloName`函数并没有 如下代码所示,我们自己实现了一个简易的路由器 ```Go - package main +package main - import ( - "fmt" - "net/http" - ) +import ( + "fmt" + "net/http" +) - type MyMux struct { - } +type MyMux struct { +} - func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { - if r.URL.Path == "/" { - sayhelloName(w, r) - return - } - http.NotFound(w, r) +func (p *MyMux) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + sayhelloName(w, r) return } + http.NotFound(w, r) + return +} - func sayhelloName(w http.ResponseWriter, r *http.Request) { - fmt.Fprintf(w, "Hello myroute!") - } +func sayhelloName(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello myroute!") +} - func main() { - mux := &MyMux{} - http.ListenAndServe(":9090", mux) - } +func main() { + mux := &MyMux{} + http.ListenAndServe(":9090", mux) +} ``` ## Go代码的执行流程