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