寫本次作業看了net/http一些函數,本篇博客主要解釋一些我在練習或使用過的api。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request))
用來註冊路由,即,自行設置路由規則,pattern爲URL的部分路徑,handler爲該路徑對應的處理函數。當pattern爲“/”時,默認匹配所有路勁。當request發送的URL,path可以匹配多個路由規則時,會把路徑以樹形的方式逐層進行匹配,“/”爲根節點,最後優先匹配到路徑最長的那個。
其中,DefaultServeMux,是ServeMux的一個默認實例。
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
DefaultServeMux.HandleFunc(pattern, handler)
}
ServeMux
var DefaultServeMux = &defaultServeMux
var defaultServeMux ServeMux
type ServeMux struct {
mu sync.RWMutex // 讀寫鎖
m map[string]muxEntry // 保存URL規則及其對應的處理函數
hosts bool // 用來判斷是否決定pattern是否包含r.Host
}
type muxEntry struct {
explicit bool // 用來標記pattern是否精確匹配
h Handler // pattern對應的處理函數
pattern string // URL規則
}
func (mux *ServeMux) Handle(pattern string, handler Handler)
ServeMux的Handle對pattern合法性進行判斷,若合法把pattern和對應的處理函數添加進默認路由
func (mux *ServeMux) Handle(pattern string, handler Handler) {
mux.mu.Lock()
defer mux.mu.Unlock()
// 判斷pattern是否合法,pattern不能爲空,爲nil或一個pattern對應多個不同的handle函數
if pattern == "" {
panic("http: invalid pattern " + pattern)
}
if handler == nil {
panic("http: nil handler")
}
if mux.m[pattern].explicit {
panic("http: multiple registrations for " + pattern)
}
// 如果mux的map爲空,需要分配一個map空間
if mux.m == nil {
mux.m = make(map[string]muxEntry)
}
// 把mux的map包裝進新的pattern和其處理函數
mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
// 如果不是“/”開頭,則在請求的時候會以“host+path”一起放進match
if pattern[0] != '/' {
mux.hosts = true
}
// Helpful behavior:
// If pattern is /tree/, insert an implicit permanent redirect for /tree.
// It can be overridden by an explicit registration.
// 如果註冊了一個路徑“/tree/”但“/tree”沒有被註冊,那麼“/tree”會被默認重定向到這個路由
n := len(pattern)
if n > 0 && pattern[n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {
// If pattern contains a host name, strip it and use remaining
// path for redirect.
path := pattern
if pattern[0] != '/' {
// In pattern, at least the last character is a '/', so
// strings.Index can't be -1.
path = pattern[strings.Index(pattern, "/"):]
}
url := &url.URL{Path: path}
mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}
}
}
func (srv *Server) Serve(l net.Listener) error
對某個端口進行監聽,接收一個剛建立的連接,併發地對每個連接建立一個新服務對象,能夠去讀取每個連接請求並調用srv.Handler去回覆這些請求。總是返回一個非空的error。
func (srv *Server) Serve(l net.Listener) error {
defer l.Close()
if fn := testHookServerServe; fn != nil {
fn(srv, l)
}
var tempDelay time.Duration // 設置接收失敗的延時時間
if err := srv.setupHTTP2_Serve(); err != nil {
return err
}
srv.trackListener(l, true)
defer srv.trackListener(l, false)
baseCtx := context.Background() // base is always background, per Issue 16220
ctx := context.WithValue(baseCtx, ServerContextKey, srv)
// 在循環中accept,建立connetion,然後處理對應的connection
for {
rw, e := l.Accept()// 調用Accept監聽
if e != nil {
select {
case <-srv.getDoneChan():
return ErrServerClosed
default:
}
if ne, ok := e.(net.Error); ok && ne.Temporary() {
if tempDelay == 0 {
tempDelay = 5 * time.Millisecond
} else {
tempDelay *= 2
}
if max := 1 * time.Second; tempDelay > max {
tempDelay = max
}
srv.logf("http: Accept error: %v; retrying in %v", e, tempDelay)
time.Sleep(tempDelay)
continue
}
return e
}
tempDelay = 0
// 建立新的連接
c := srv.newConn(rw)
c.setState(c.rwc, StateNew)
go c.serve(ctx)// 併發地處理請求
}
}