1. net/http初识
1.1 服务端
import ( "fmt" "net/http" ) func main() { http.HandleFunc("/smoke", func(w http.ResponseWriter, r *http.Request) { w.Write([]byte("ok!")) }) err := http.ListenAndServe(":8080", nil) if err != nil { panic(err) } }
说明:本地启动一个server端监听8080
端口,并且提供路由/smole获取信息;
1.2 客户端
import ( "fmt" "io/ioutil" "net/http" ) func main() { resp, err := http.DefaultClient.Get("http://127.0.0.1:8080/smoke") if err != nil { fmt.Printf("get failed, err:%v\n", err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Printf("read from resp.body failed, err:%v\n", err) return } fmt.Println(string(body)) }
2. Server源码解析
2.1 Server
type Server struct { // server地址 Addr string // 路由处理器 Handler Handler ... }
整个http服务端封装在Server中,Handler是Server中最核心的成员字段,实现从请求路径path到具体处理函数handler到注册和映射能力
在用户构造Server对象时,倘若其中的Handler字段未显示声明,则会取包下的单例对象DefaultServerMux(ServerMux类型)兜底
2.2 Handler
Handler是一个interface,定义了ServeHTTP方法
该方法的作用:根据http请求Request中的请求路径path映射到对应的handler处理函数,对请求进行处理响应
type Handler interface { ServeHTTP(ResponseWriter, *Request) }
2.3 ServerMux
SeverMux是对Handler的具体实现,内部通过一个map维护从path到handler到映射关系
type ServeMux struct { mu sync.RWMutex m map[string]muxEntry es []muxEntry // slice of entries sorted from longest to shortest. hosts bool // whether any patterns contain hostnames }
说明:读写锁mu保证ServerMux里map的安全性、es在前置匹配的时候用到
2.4 muxEntry
muxEntry是一个handle单元,内部包含了请求路径path(冗余了) + 处理函数handler两部分
type muxEntry struct { h Handler pattern string }
注意:2.1 Server中和Handler和2.4 muxEntry中的Handler协议是一样的,但是功能不一样(2.1 路由处理、2.4 注册的handler处理函数)
2.5 注册handler流程
http.HandleFunc --> ServeMux.HandleFunc --> ServeMux.Handle
2.5.1 http.HandleFunc
当用户直接使用http.HandleFunc注册handler时,则会将其注册到默认的DefaultServerMux中
// DefaultServeMux is the default ServeMux used by Serve. var DefaultServeMux = &defaultServeMux var defaultServeMux ServeMux
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }
2.5.2 ServeMux.HandleFunc
ServeMux.HandleFunc内部会将处理函数handler转为实现了ServeHTTP方法HandlerFunc类型,将其作为Handler interface的实现类注册到ServeMux的路由map中
type HandlerFunc func(ResponseWriter, *Request) // ServeHTTP calls f(w, r). func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r) } func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { if handler == nil { panic("http: nil handler") } mux.Handle(pattern, HandlerFunc(handler)) }
2.5.3 ServeMux.Handle
将path和handler包装成一个muxEntry,以path为key注册到路由map(ServeMux.m)
响应模糊匹配机制,对于'/'结尾的path,根据path长度将muxEntry有序插入到数组ServeMux.es中
func (mux *ServeMux) Handle(pattern string, handler Handler) { mux.mu.Lock() defer mux.mu.Unlock() // ... e := muxEntry{h: handler, pattern: pattern} mux.m[pattern] = e if pattern[len(pattern)-1] == '/' { mux.es = appendSorted(mux.es, e) } // ... }
2.6 服务端启动
2.6.1 ListenAndServe
声明一个Server对象,嵌套执行ListenAndServe()方法
func ListenAndServe(addr string, handler Handler) error { server := &Server{Addr: addr, Handler: handler} return server.ListenAndServe() }
注意:如何传入的handler为空,会使用默认的DefaultServeMux
2.6.2 ListenAndServe()方法
根据用户传进来的端口,申请一个监听器listener,继而调用Server.Serve方法
func (srv *Server) ListenAndServe() error { // ... addr := srv.Addr if addr == "" { addr = ":http" } ln, err := net.Listen("tcp", addr) if err != nil { return err } return srv.Serve(ln) }
2.6.3 Server.Serve
func (srv *Server) Serve(l net.Listener) error { baseCtx := context.Background() // ... ctx := context.WithValue(baseCtx, ServerContextKey, srv) for { rw, err := l.Accept() // ... connCtx := ctx // ... c := srv.newConn(rw) // ... go c.serve(connCtx) } }
如果有请求到来,就会走到Accept()方法,获取一个连接conn,启一个协程处理
2.6.4 serve方法
通过ctx将请求参数Request读出来,调用ServeHTTP做真正的请求处理
func (c *conn) serve(ctx context.Context) { // ... c.r = &connReader{conn: c} c.bufr = newBufioReader(c.r) c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) for { w, err := c.readRequest(ctx) // ... serverHandler{c.server}.ServeHTTP(w, w.req) w.cancelCtx() } }
2.6.5 ServeHTTP方法
首先会判断Handler做判断,如果没声明,则取全局单例DefaultServeMux进行路由匹配,调用ServeHTTP处理
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) { handler := sh.srv.Handler if handler == nil { handler = DefaultServeMux } // ... handler.ServeHTTP(rw, req) }
2.6.6 ServeMux.ServeHTTP
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) { // ... h, _ := mux.Handler(r) h.ServeHTTP(w, r) }
2.6.7 ServeMux.Handler
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) { // ... return mux.handler(host, r.URL.Path) }
2.6.8 ServeMux.handler
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) { mux.mu.RLock() defer mux.mu.RUnlock() // ... h, pattern = mux.match(path) // ... return }
说明:当通过路由字典Server.m未命中handler,此时会启动模糊匹配,有两个核心规则
1)以'/'结尾的pattern才能被添加到Server.es数组中,才有资格参与模糊匹配
2)模糊匹配时,会找到一个与请求路径path前缀完全匹配且长度最长的pattern,其对应的handler为本次处理函数
3. Client源码解析
3.1 Client
Transport:负责http通信核心部分
Jar:cookie管理
Timeout:超时处理
type Client struct {
// If nil, DefaultTransport is used. Transport RoundTripper // ... Jar CookieJar Timeout time.Duration }
3.2 RoundTripper
RoundTripper是通信模块的interface,需要实现方法RoundTrip,即通过传入请求Request,与服务端交互后获得响应Response
type RoundTripper interface { RoundTrip(*Request) (*Response, error) }
3.3 Transport
Transport是RoundTripper的实现类,核心字段:
idleConn:空闲连接map,实现复用
DialContext:新连接生成器
type Transport struct { idleConn map[connectMethodKey][]*persistConn // most recently used at end // ... DialContext func(ctx context.Context, network, addr string) (net.Conn, error) // ... }
3.4 Request
type Request struct { // 方法 Method string
// 请求路径 URL *url.URL // 请求头 Header Header // 请求参数内容 Body io.ReadCloser // 服务器主机 Host string // query请求参数 Form url.Values // 响应参数 Response *Response // 请求链路的上下文 ctx context.Context
// ... }
3.5 请求流程
ServeMux用于注册URL和handler的对应关系,并自动把请求转发到对应的handler进行处理
注意:http.ListenAndServe(":8080", nil)中的nil