go|go http模块源码分析-server端

前言 近期使用go开发api后台服务,对http模块源码有初步了解,所以整理总结一下。
server端核心模型包括

  • Server 类型结构,代表了一个指定端口下的服务。
同时也保存了tls,超时等配置。最重要的是一个handler处理器。
type Server struct { Addrstring// TCP address to listen on, ":http" if empty Handler Handler // handler to invoke, http.DefaultServeMux if nil TLSConfig *tls.Config ReadTimeout time.Duration //... }

ListenAndServe方法开启监听,等待连接。
server 监听客户端请求,启动goroutine处理。
func (srv *Server) Serve(l net.Listener) error { //... for { rw, e := l.Accept() // ... c := srv.newConn(rw) go c.serve(ctx) } }

  • Handler 接口,响应一个http请求
type Handler interface { ServeHTTP(ResponseWriter, *Request) }

  • ServeMux : http请求多路复用器,实现了 Handler接口,它的实现为: 转发请求到匹配的handler处理。
type ServeMux struct { musync.RWMutex mmap[string]muxEntry es[]muxEntry // slice of entries sorted from longest to shortest. hosts bool// whether any patterns contain hostnames }// 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) }

  • DefaultServeMux: 是ServeMux类型一个实力, 作为一个全局对象导出。当新建的server对象,handler为空时,使用DefaultServeMux。
// DefaultServeMux is the default ServeMux used by Serve. var DefaultServeMux = &defaultServeMuxvar defaultServeMux ServeMux

可以通过HandleFunc方法,向全局多路复用器中加入路由模式及其handler。
处理请求时根据所有加入的路由模式中匹配。
// HandleFunc registers the handler function for the given pattern // in the DefaultServeMux. // The documentation for ServeMux explains how patterns are matched. func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { DefaultServeMux.HandleFunc(pattern, handler) }

注册pattern, 如果以/结尾,会加入到排序的切片中,在map中匹配不到路由时,使用它,做最长匹配。
if pattern[len(pattern)-1] == '/' { mux.es = appendSorted(mux.es, e) }

路由匹配规则,先在map中精确匹配。
匹配失败则 用到排序的slice 进行最长匹配。
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, "" }

总结:
    1. go的http server模块同时也包含了处理socker 连接的代码,所以不需要像java需要额外的应用服务器,例如tomcat。 go更易于部署,开发迭代。
      我认为一部分原因 是得益于go对并发的原生支持,go的并发模型。go开发时,可以使用goroute简单 并且低代价的方式,即可获得高并发的支持。
    1. go server中路由匹配 力度太大,一个url匹配一个handler,不区分http方法,也无法在url中加入参数匹配。
      所以 路由部分 还是建议使用开源模块
      https://github.com/gorilla/mux
      https://github.com/julienschmidt/httprouter
      mux源码分析参考 : 这里
参考:
https://www.godoc.org/net/http
【go|go http模块源码分析-server端】原文链接

    推荐阅读