This is a creation in Article, where the information may have evolved or changed. As mentioned in the previous article
API Server
Need to set
HTTP
handler function:
......server.SetHandler(api.NewPrimary(cl, tlsConfig, &statusHandler{cl, nil, nil}, c.GlobalBool("debug"), c.Bool("cors")))......
api.Server
The structure is defined as follows:
// Server is a Docker API server.type Server struct { hosts []string tlsConfig *tls.Config dispatcher *dispatcher}
HTTP
the methods in which the request is processed are as follows:
// 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
All that is done is to handler
assign to Server.dispatcher.handler
. handler
the type is HTTP. Handler:
type Handler interface { ServeHTTP(ResponseWriter, *Request)}
api.NewPrimary
Using the MUX this 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}
and *mux.Router
ServeHTTP
This method is implemented, so it conforms to http.Handler
this 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()
function defines a new http.Server
variable, using the method implemented above api.Server.dispatcher
ServeHTTP
to respond to the HTTP
request:
server = &http.Server{ Addr: protoAddrParts[1], Handler: s.dispatcher, }
Look at setupPrimaryRouter
this function again:
Func Setupprimaryrouter (R *mux. Router, Context *context, enablecors bool) {for method, mappings: = Range Routes {for route, FCT: = Range Mapp Ings {log. Withfields (log. Fields{"Method": Method, "route": Route}). Debug ("Registering HTTP route") Localroute: = route LOCALFCT: = FCT Wrap: = Func (w HTTP.R Esponsewriter, 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)}}}}
These routes
are defined as follows:
var routes = map[string]map[string]handler{ "HEAD": { "/containers/{name:.*}/archive": proxyContainer, }, "GET": { "/_ping": ping, "/events": getEvents, "/info": getInfo, ...... } ......}
To
"HEAD": { "/containers/{name:.*}/archive": proxyContainer,}
For example:
method
and localMethod
Yes "HEAD"
;
mappings
Is:
{ "/containers/{name:.*}/archive": proxyContainer,}
route
and localRoute
Yes "/containers/{name:.*}/archive"
;
fct
and localFct
Yes proxyContainer
.
So
r.Path("/v{version:[0-9]+.[0-9]+}" + localRoute).Methods(localMethod).HandlerFunc(wrap)r.Path(localRoute).Methods(localMethod).HandlerFunc(wrap)
is to "/v*/containers/{name:.*}/archive"
"/containers/{name:.*}/archive"
Register the function with this operation, and the PATH
"HEAD"
wrap
wrap
function is encapsulated localFct
, that is, the proxyContainer
function. In addition, the if enableCors
section is similar to the above.