This is a creation in Article, where the information may have evolved or changed.
Original link: http://targetliu.com/golang-http-router/
Still on the way to go, I used PHP to eat over-reliance on the framework of the loss. Now when you learn go, you decide to start with the basics and learn from the standard library.
SOURCE Analysis
We know that the simplest way to build HTTP server code is basically this:
http.HandleFunc('/', func(w http.ResponseWriter, r *http.Request){ fmt.Fprint(w, "Hello world")})http.ListenAndServe(":8080", nil)
This will successfully establish a listening 8080
port of the HTTP server, when access to the output Hello world
Let's HandleFunc
take a look at what we've done:
func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler)}
Here we continue to DefaultServeMux
register the route by invoking the HandleFunc
method, this DefaultServeMux
again He Shan:
type ServeMux struct { mu sync.RWMutex m map[string]muxEntry hosts bool // whether any patterns contain hostnames}type muxEntry struct { explicit bool h Handler pattern string}// NewServeMux allocates and returns a new ServeMux.func NewServeMux() *ServeMux { return new(ServeMux) }// DefaultServeMux is the default ServeMux used by Serve.var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux
DefaultServeMux
is net/http
a default type provided by the package ServeMux
, which ServeMux
implements the Handler
interface.
To find out, the HTTP server received a request by go c.serve(ctx)
opening goroutine
processing the request, in this process called the Handler
interface function ServeHTTP
to do further processing (such as matching methods, links, etc.).
So, we can understand ServeMux
that it's net/http
a built-in routing feature.
Continue to HandleFunc
come back to:
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { mux.Handle(pattern, HandlerFunc(handler))}
ServeMux
HandleFunc
method converts our incoming route-specific implementation function into a HandlerFunc
type and registers it with a Handle
route. This HandlerFunc
type also implements the Handler
interface:
type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { f(w, r)}
Finally to Handle
this method, the Handle
method by the pattern
path and the implementation of the Handler
interface method one by one corresponding to the save to ServeMux
the map[string]muxEntry
next request when the call. Therefore, you can also Handle
register a route by passing directly to a Handler
method that implements the interface.
At this point, net/http
the registration process for the default route in the package has basically gone.
As for the routing call at the time of the request, remember to ServeHTTP
find map
the corresponding path in the lookup and call the relevant method.
Home-made routing
Through the above analysis, we can leaf out and implement our own routing function.
package routeimport ( "net/http" "strings")//返回一个Router实例func NewRouter() *Router { return new(Router)}//路由结构体,包含一个记录方法、路径的maptype Router struct { Route map[string]map[string]http.HandlerFunc}//实现Handler接口,匹配方法以及路径func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { if h, ok := r.Route[req.Method][req.URL.String()]; ok { h(w, req) }}//根据方法、路径将方法注册到路由func (r *Router) HandleFunc(method, path string, f http.HandlerFunc) { method = strings.ToUpper(method) if r.Route == nil { r.Route = make(map[string]map[string]http.HandlerFunc) } if r.Route[method] == nil { r.Route[method] = make(map[string]http.HandlerFunc) } r.Route[method][path] = f}
Use:
r := route.NewRouter()r.HandleFunc("GET", "/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "Hello Get!")})r.HandleFunc("POST", "/", func(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "hello POST!")})http.ListenAndServe(":8080", r)
This example is just a simple function implementation of leaf out.
A complete routing framework should contain more complex matching, error detection and so on, you can try to try it yourself.
Reading the source code and repeating the wheel are all ways to learn.
Finally, you are welcome to follow my blog http://targetliu.com/