关键的代码是第137行将需要返回的response和reques
func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {handler := sh.srv.Handlerif handler == nil {handler = DefaultServeMux}if req.RequestURI == "*" && req.Method == "OPTIONS" {handler = globalOptionsHandler{}}if req.URL != nil && strings.Contains(req.URL.RawQuery, ";") {var allowQuerySemicolonsInUse int32req = req.WithContext(context.WithValue(req.Context(), silenceSemWarnContextKey, func() {atomic.StoreInt32(&allowQuerySemicolonsInUse, 1)}))defer func() {if atomic.LoadInt32(&allowQuerySemicolonsInUse) == 0 {sh.srv.logf("http: URL query contains semicolon, which is no longer a supported separator; parts of the query may be stripped when parsed; see golang.org/issue/25192")}}()}handler.ServeHTTP(rw, req)}
在这里我们终于又和注册路由时候使用的DefaultServeMux见面了,因为在启动服务的时候handler传入的是nil,所以这里默认的使用DefaultServeMux,然而此时的DefaultServeMux已经包含了注册的路由 。接下来我们来看看DefaultServeMux的ServeHTTP()是如何实现的 。
// ServeHTTP dispatches the request to the handler whose// pattern most closely matches the request URL.func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {if r.RequestURI == "*" {if r.ProtoAtLeast(1, 1) {w.Header().Set("Connection", "close")}w.WriteHeader(StatusBadRequest)return}h, _ := mux.Handler(r)h.ServeHTTP(w, r)}
第11行就是通过通过请求中的路由再返回路由对应的处理函数
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {// CONNECT requests are not canonicalized.if r.Method == "CONNECT" {// If r.URL.Path is /tree and its handler is not registered,// the /tree -> /tree/ redirect applies to CONNECT requests// but the path canonicalization does not.if u, ok := mux.redirectToPathSlash(r.URL.Host, r.URL.Path, r.URL); ok {return RedirectHandler(u.String(), StatusMovedPermanently), u.Path}return mux.handler(r.Host, r.URL.Path)}// All other requests have any port stripped and path cleaned// before passing to mux.handler.host := stripHostPort(r.Host)path := cleanPath(r.URL.Path)// If the given path is /tree and its handler is not registered,// redirect for /tree/.if u, ok := mux.redirectToPathSlash(host, path, r.URL); ok {return RedirectHandler(u.String(), StatusMovedPermanently), u.Path}if path != r.URL.Path {_, pattern = mux.handler(host, path)u := &url.URL{Path: path, RawQuery: r.URL.RawQuery}return RedirectHandler(u.String(), StatusMovedPermanently), pattern}return mux.handler(host, r.URL.Path)}
第32行然后接着往下走
func (mux *ServeMux) handler(host, path string) (h Handler, pattern string) {mux.mu.RLock()defer mux.mu.RUnlock()// Host-specific pattern takes precedence over generic onesif mux.hosts {h, pattern = mux.match(host + path)}if h == nil {h, pattern = mux.match(path)}if h == nil {h, pattern = NotFoundHandler(), ""}return}
第7行
func (mux *ServeMux) match(path string) (h Handler, pattern string) {// Check for exact match first.v, ok := mux.m[path]if ok {return v.h, v.pattern}// Check for longest valid match.mux.es contains all patterns// that end in / sorted from longest to shortest.for _, e := range mux.es {if strings.HasPrefix(path, e.pattern) {return e.h, e.pattern}}return nil, ""}
第3~5行,如请求的路由有对应的处理函数则返回对应的处理函数 。得到了对应的处理函数,然后调用处理函数实现的ServeHTTP()的逻辑
// The HandlerFunc type is an adapter to allow the use of// ordinary functions as HTTP handlers. If f is a function// with the appropriate signature, HandlerFunc(f) is a// Handler that calls f.type HandlerFunc func(ResponseWriter, *Request)// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {f(w, r)}
通过刚开始注册路由的时候我们传入的处理函数是HandlerFunc类型,而且对应的ServeHTTP()逻辑是运行处理函数,所以到这里逻辑就走到了我们的业务逻辑了,这就是使用golang原生http包实现的http服务具体的实现过程 。
接着我们来看看gin的http服务有什么不同,gin中匹配路由和处理函数的的数据结构是Radix Tree,这是前缀树的优化方案
func (engine *Engine) addRoute(method, path string, handlers HandlersChain) {assert1(path[0] == '/', "path must begin with '/'")assert1(method != "", "HTTP method can not be empty")assert1(len(handlers) > 0, "there must be at least one handler")debugPrintRoute(method, path, handlers)root := engine.trees.get(method)if root == nil {root = new(node)root.fullPath = "/"engine.trees = append(engine.trees, methodTree{method: method, root: root})}root.addRoute(path, handlers)// Update maxParamsif paramsCount := countParams(path); paramsCount > engine.maxParams {engine.maxParams = paramsCount}if sectionsCount := countSections(path); sectionsCount > engine.maxSections {engine.maxSections = sectionsCount}}
推荐阅读
- 如何修改WordPress后台的登录界面?
- 如何购买一台性价比较高的电脑
- SQL如何删除重复数据
- 如何去掉电脑桌面的小黄锁?
- 春季呼吸道疾病高发 老人小孩如何预防感冒
- 肝好不好看身体6部位 春季如何巧补肝
- 红茶柠檬的功效,红茶和柠檬蜂蜜的功效与作用
- 房屋未住物业费如何收?
- 杨幂|杨幂简直是“行走的衣架子”,她是如何把极简风穿出氛围美的?
- 喝茶与品茶区别,如何区别高山与坝系普洱茶香气