這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。在上一篇提到的
API Server需要設定
HTTP處理函數:
......server.SetHandler(api.NewPrimary(cl, tlsConfig, &statusHandler{cl, nil, nil}, c.GlobalBool("debug"), c.Bool("cors")))......
api.Server結構體定義如下:
// Server is a Docker API server.type Server struct { hosts []string tlsConfig *tls.Config dispatcher *dispatcher}
其中處理HTTP請求的相關方法如下:
// Dispatcher is a meta http.Handler. It acts as an http.Handler and forwards// requests to another http.Handler that can be changed at runtime.type dispatcher struct { handler http.Handler}// SetHandler changes the underlying handler.func (d *dispatcher) SetHandler(handler http.Handler) { d.handler = handler}// ServeHTTP forwards requests to the underlying handler.func (d *dispatcher) ServeHTTP(w http.ResponseWriter, r *http.Request) { if d.handler == nil { httpError(w, "No dispatcher defined", http.StatusInternalServerError) return } d.handler.ServeHTTP(w, r)}// SetHandler is used to overwrite the HTTP handler for the API.// This can be the api router or a reverse proxy.func (s *Server) SetHandler(handler http.Handler) { s.dispatcher.SetHandler(handler)}
Server.SetHandler所做的就是把handler賦給Server.dispatcher.handler。handler類型是http.Handler:
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
api.NewPrimary利用了mux這個project:
// NewPrimary creates a new API router.func NewPrimary(cluster cluster.Cluster, tlsConfig *tls.Config, status StatusHandler, debug, enableCors bool) *mux.Router { // Register the API events handler in the cluster. eventsHandler := newEventsHandler() cluster.RegisterEventHandler(eventsHandler) context := &context{ cluster: cluster, eventsHandler: eventsHandler, statusHandler: status, tlsConfig: tlsConfig, } r := mux.NewRouter() setupPrimaryRouter(r, context, enableCors) if debug { profilerSetup(r, "/debug/") } return r}
而*mux.Router實現了ServeHTTP這個方法,所以符合http.Handler這個interface:
// ServeHTTP dispatches the handler registered in the matched route.//// When there is a match, the route variables can be retrieved calling// mux.Vars(request).func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { ......}
api.Server的ListenAndServe()函數定義了新的http.Server變數,利用上面實現的api.Server.dispatcher的ServeHTTP方法來響應HTTP請求:
server = &http.Server{ Addr: protoAddrParts[1], Handler: s.dispatcher, }
再看一下setupPrimaryRouter這個函數:
func setupPrimaryRouter(r *mux.Router, context *context, enableCors bool) { for method, mappings := range routes { for route, fct := range mappings { log.WithFields(log.Fields{"method": method, "route": route}).Debug("Registering HTTP route") localRoute := route localFct := fct wrap := func(w http.ResponseWriter, r *http.Request) { log.WithFields(log.Fields{"method": r.Method, "uri": r.RequestURI}).Debug("HTTP request received") if enableCors { writeCorsHeaders(w, r) } context.apiVersion = mux.Vars(r)["version"] localFct(context, w, r) } localMethod := method r.Path("/v{version:[0-9]+.[0-9]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap) r.Path(localRoute).Methods(localMethod).HandlerFunc(wrap) if enableCors { optionsMethod := "OPTIONS" optionsFct := optionsHandler wrap := func(w http.ResponseWriter, r *http.Request) { log.WithFields(log.Fields{"method": optionsMethod, "uri": r.RequestURI}). Debug("HTTP request received") if enableCors { writeCorsHeaders(w, r) } context.apiVersion = mux.Vars(r)["version"] optionsFct(context, w, r) } r.Path("/v{version:[0-9]+.[0-9]+}" + localRoute). Methods(optionsMethod).HandlerFunc(wrap) r.Path(localRoute).Methods(optionsMethod). HandlerFunc(wrap) } } }}
其中routes定義如下:
var routes = map[string]map[string]handler{ "HEAD": { "/containers/{name:.*}/archive": proxyContainer, }, "GET": { "/_ping": ping, "/events": getEvents, "/info": getInfo, ...... } ......}
以
"HEAD": { "/containers/{name:.*}/archive": proxyContainer,}
為例:
method和localMethod是"HEAD";
mappings是:
{ "/containers/{name:.*}/archive": proxyContainer,}
route和localRoute是"/containers/{name:.*}/archive";
fct和localFct是proxyContainer。
所以
r.Path("/v{version:[0-9]+.[0-9]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap)r.Path(localRoute).Methods(localMethod).HandlerFunc(wrap)
就是為"/v*/containers/{name:.*}/archive"和"/containers/{name:.*}/archive"這個PATH的"HEAD"操作註冊了wrap函數,而wrap函數則封裝了localFct,也就是proxyContainer函數。 另外,if enableCors部分與上述類似。