只需要幾行程式碼就可以啟動http服務
func main() {
http.HandleFunc("/", sayHelloWorld) //路由處理, sayHelloWorld是函式變數, handler func(ResponseWriter, *Request)
err := http.ListenAndServe(":9091", nil) //監聽9091埠
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}
1.路由處理-ServeMux
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
}
http包會有個全域性ServeMux,也就是DefaultServeMux,所以一般不用我們例項它
1.1註冊路由
type HandlerFunc func(ResponseWriter, *Request) //定義了函式類,這個類的變數都實現了介面http.Handler
// HandleFunc registers the handler function for the given pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
mux.Handle(pattern, HandlerFunc(handler))
}
func (mux *ServeMux) Handle(pattern string, handler Handler) {
e := muxEntry{h: handler, pattern: pattern}
mux.m[pattern] = e //實際註冊到ServeMux.m屬性中
}
2.服務物件-Serve
type Server struct {
Addr string
Handler Handler // handler to invoke, http.DefaultServeMux if nil
TLSConfig *tls.Config
ReadTimeout time.Duration
ReadHeaderTimeout time.Duration
WriteTimeout time.Duration
IdleTimeout time.Duration
MaxHeaderBytes int
TLSNextProto map[string]func(*Server, *tls.Conn, Handler)
ConnState func(net.Conn, ConnState)
ErrorLog *log.Logger
BaseContext func(net.Listener) context.Context
ConnContext func(ctx context.Context, c net.Conn) context.Context
inShutdown atomicBool // true when when server is in shutdown
disableKeepAlives int32 // accessed atomically.
nextProtoOnce sync.Once // guards setupHTTP2_* init
nextProtoErr error // result of http2.ConfigureServer if used
mu sync.Mutex
listeners map[*net.Listener]struct{}
activeConn map[*conn]struct{}
doneChan chan struct{}
onShutdown []func()
}
2.1.監聽埠
func ListenAndServe(addr string, handler Handler) error {
server := &Server{Addr: addr, Handler: handler} //handler一開始是nil
return server.ListenAndServe()
}
func (srv *Server) ListenAndServe() error {
addr := srv.Addr
ln, err := net.Listen("tcp", addr) //透過net監聽埠,net.listener
return srv.Serve(ln)
}
func (srv *Server) Serve(l net.Listener) error {
for {
rw, err := l.Accept() //監聽到客戶端有連線,返回net.conn
c := srv.newConn(rw) //把net.conn封裝為http.conn
go c.serve(connCtx)
}
}
2.2 連線物件-http.conn
type conn struct {
server *Server
cancelCtx context.CancelFunc
rwc net.Conn
remoteAddr string
tlsState *tls.ConnectionState
werr error
// r is bufr's read source. It's a wrapper around rwc that provides
// io.LimitedReader-style limiting (while reading request headers)
// and functionality to support CloseNotifier. See *connReader docs.
r *connReader
// bufr reads from r.
bufr *bufio.Reader
// bufw writes to checkConnErrorWriter{c}, which populates werr on error.
bufw *bufio.Writer
// lastMethod is the method of the most recent request
// on this connection, if any.
lastMethod string
curReq atomic.Value // of *response (which has a Request in it)
curState struct{ atomic uint64 } // packed (unixtime<<8|uint8(ConnState))
// mu guards hijackedv
mu sync.Mutex
// hijackedv is whether this connection has been hijacked
// by a Handler with the Hijacker interface.
// It is guarded by mu.
hijackedv bool
}
處理連線
func (c *conn) serve(ctx context.Context) {
c.remoteAddr = c.rwc.RemoteAddr().String()
c.r = &connReader{conn: c}
c.bufr = newBufioReader(c.r)
c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
for {
w, err := c.readRequest(ctx) //獲取request物件,response物件
c.curReq.Store(w)
serverHandler{c.server}.ServeHTTP(w, w.req) //把requset,response交個路由器處理
w.cancelCtx()
c.rwc.SetReadDeadline(time.Time{})
}
}
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {
handler := sh.srv.Handler //一開始listenAndServe時,Handler是nil.
if handler == nil {
handler = DefaultServeMux
}
handler.ServeHTTP(rw, req) //最終交給DefaultServeMux處理
}
2.3.路由分發
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {
h, _ := mux.Handler(r) //查詢路由獲取對應的HandlerFunc
h.ServeHTTP(w, r)
}
3.1根據path獲取handler
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
返回http.Handler,註冊的函式都實現了http.Handler介面。
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
host := stripHostPort(r.Host)
path := cleanPath(r.URL.Path)
return mux.handler(host, r.URL.Path)
}
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {
h, pattern = mux.match(path)
return
}
func (mux *ServeMux) match(path string) (h Handler, pattern string) {
// Check for exact match first.
v, ok := mux.m[path]
if ok {
return v.h, v.pattern
}
return nil, ""
}
總結
1.ServeMux 等於srv.Handler,儲存了路由map,實現了ServeHTTP()方法(conn會把w,r傳到這個方法去),很多自定義http服務,都是重寫srv.Handler
2.Serve 監聽埠,管理連線
3.介面Handler 註冊路由的函式必須實現這個介面,為了方便專門定義了一個型別HandlerFunc,只要是HandlerFunc型別的變數,就是實現了介面Handler
type HandlerFunc func(ResponseWriter, *Request)
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
f(w, r)
}
4.serverHandler 獨立的結構,為了串聯conn與srv.Handler
在conn連線物件中,接受的請求透過serverHandler{c.server}.ServeHTTP(w, w.req),最終handler.ServeHTTP()
區塊鏈節點使用http包實現json-rpc功能
構造httpServer物件,作為srv.Handler. 連線物件會把w,r傳給httpServer的ServeHTTP方法
func (h *httpServer) start() error {
h.server = &http.Server{Handler: h} //建立標準庫srv, srv.Handler為httpServer
listener, err := net.Listen("tcp", h.endpoint)
h.listener = listener
go h.server.Serve(listener)
return nil
}
-------------------------------------------------
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rpc := h.httpHandler.Load().(*rpcHandler) //這個是rpc.NewServer()建立的
rpc.ServeHTTP(w, r)//又轉給rpcHandler
return
}
這裡其實是多封裝了一層,最終處理的Handler物件是rpc.NewServer(),所有這個rpcHandler等於標準庫的srv.Handler,需要儲存路由map,同時實現ServeHTTP方法。
本作品採用《CC 協議》,轉載必須註明作者和本文連結