Golang net/http原始碼筆記/路由運作原理

Changheng Liou
4 min readAug 11, 2018

--

This is a walkthrough about the HTTP multiplexer(router) in the net/http package. Let me know if I need to write this in English.

熟悉Golang的朋友都知道,一個簡單的webserver的寫法大概如下

簡單易懂,只要符合http.ResponseWriter, *http.Request的function都可以被當作routing handler,但這篇主要不是介紹他的用法,而是介紹它的原始碼,它底層是如何運作,開始之前先說這片是講net/http包,而不是其他功能較完備的第三方router,如gorilla/muxhttprouter等等

以下正文&一大堆Source Code:

這是在呼叫ListenAndServe後所發生的事情,基本上該注意的地方只有Handler(定義參考下面)那邊,一般來說第二個參數給nil,並使用內建的Router就可,而在這邊若有實現自己的Router,則會在這邊創建為server的handler,之後server會呼叫自己的ListenAndServe,基本上就是一些tcp的連線,如呼叫net.Tcp(“tcp”, addr),並開一個for loop去每一個請求都另起一個goroutine並呼叫

來處理每個連線。

題外話,很有名的fasthttp有實作自己的workerpool,類似線程池的概念,因此據說比net/http快很多,這邊我並沒有看過原始碼也沒有實際玩過,而且這篇的重點並不是在tcp建立連線等等,在此不多做討論,以router相關原始碼為主。

在每個context.serve底下,處理完io和底層的一些tcp後,便呼叫以下的函數

這邊handler就是剛剛ListenAndServe第二個參數所傳進去的值,若沒有傳入則用預設值,而預設值其實就是底下的ServeMux。muxEntry則是一個map用來儲存([路徑]routing func)。最後Handler 是任意一個實現ServeHttp方法的interface。

而在剛剛server.ServeHttp的最後一行,可以看到以下mux.ServeHttp被呼叫

這個方法沒什麼特別的,基本上只是看看Request URI是否合法,之後便呼叫mux的Handler函數以取得routing function和URL pattern,

而函數中間也只是一些URL的解析,如:取得port和host、以及把www.xyz.com/tree轉至www.xyz.com/tree/等等。之後在最後一行呼叫mux.handler方法

這裡會再呼叫match方法,其實就是進muxEntry的map裡面找看看當前的path有沒有符合的routing function,若沒有完全一致的則找最長符合字串,如/category/apple/會比/category/還要好,有興趣的可以自己參考原始碼中的mux.match函數。

到這邊你可能會問,如果不寫自己的mux(router),那開頭的http.HandleFunc是怎麼把routing function給寫進去的呢?

答案就在以下這裡

這邊呼叫http.HandleFunc會把你寫的routing func直接傳給預設的mux

而你所寫的routing function等於HandleFunc這個type,然後藉由剛剛mux.ServeHTTP函數的最後一行h.ServeHTTP呼叫這個函數,最後在這個函數裡呼叫你所提供的routing function!

總結,這整個路由的過程大概如下

  1. 首先用http.HandleFunc註冊routing func
  2. 先後呼叫了DefaultServeMux的HandleFunc和Handle,並往handler 也就是map[string]muxEntry中註冊對應的路由規則
  3. 創建server並呼叫ListenAndServe
  4. 進入serveHandler.ServeHTTP以後若有自己實現的mux則使用自定的mux,沒有則使用預設的DefaultServeMux
  5. 呼叫mux.ServeHTTP
  6. 呼叫mux.Handler解析URL相關資訊,如host等
  7. 呼叫mux.handler去muxEntry中比對符合的路徑並回傳相應的handler
  8. 呼叫handler.ServeHTTP,要注意的是這邊它已經幫你轉換型別至HandlerFunc,並實現ServeHTTP,因此由這個函數呼叫你所寫好的routing function

大概是這樣,剛寫golang不到一個月,若有哪邊不懂或是有誤再請各位告知,感謝~

--

--

Changheng Liou
Changheng Liou

Written by Changheng Liou

Yet another mediocre human being.

No responses yet