Go语言中的HTTPServer:HTTP服务器,顾名思义,支持http协议的服务器,HTTP是一种简单的请求-响应协议,通常运行在TCP之上。客户端向服务器发送请求以获得相应的响应。HTTP服务简单实现packagemainimport("fmt""net/http")//③处理请求并返回结果funcHello(whttp.ResponseWriter,r*http.Request){fmt.Fprintln(w,"helloworld")}funcmain(){//①路由注册http.HandleFunc("/",Hello)//②服务监听http.ListenAndServe(":8080",nil)}是不是觉得这就结束了,这不才刚刚开始。源码分析①路由注册funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){DefaultServeMux.HandleFunc(pattern,handler)}什么是DefaultServeMux?DefaultServeMux是ServeMux的一个实例。ServeMux又是什么?//DefaultServeMuxisthedefaultServeMuxusedbyServe.varDefaultServeMux=&defaultServeMuxvardefaultServeMuxServeMuxtypeServeMuxstruct{musync.RWMutexmmap[string]muxEntryhostsbool}typemuxEntrystruct{explicitboolhHandlerpatternstring}ServeMux主要通过map[string]muxEntry,来存储了具体的url模式和handler(此handler是实现Handler接口类型)。通过实现Handler的ServeHTTP方法来匹配路由(这个在下面的源码中会提到),很多地方都会涉及到Handler,那么什么是Handler呢?typeHandlerinterface{ServeHTTP(ResponseWriter,*Request)}这个接口可以看作是HTTPServer的一个hubfunc(mux*ServeMux)HandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){mux.Handle(pattern,HandlerFunc(handler))}typeHandlerFuncfunc(ResponseWriter,*Request)func(fHandlerFunc)ServeHTTP(wResponseWriter,r*Request){f(w,r)}从代码中可以看出HandlerFunc是一个函数类型,实现了Handler接口。当调用HandleFunc()强制Hello为HandlerFunc类型时,意味着Hello函数也实现了ServeHTTP方法。ServeMux的句柄方法:func(mux*ServeMux)Handle(patternstring,handlerHandler){mux.mu.Lock()defermux.mu.Unlock()ifpattern=""{panic("http:invalidpattern"+pattern)}ifhandler==nil{panic("http:nilhandler")}ifmux.m[pattern].explicit{panic("http:multipleregistrationsfor"+pattern)}ifmux.m==nil{mux.m=make(map[string]muxEntry)}//将handler和patternpattern绑定到map上//map[string]muxEntrymux.m[pattern]=muxEntry{explicit:true,h:handler,pattern:pattern}ifpattern[0]!='/'{mux.hosts=true}//这个是绑定静态目录,不是本片的重点。n:=len(pattern)ifn>0&&pattern[n-1]=='/'&&!mux.m[pattern[0:n-1]].explicit{path:=patternifpattern[0]!='/'{path=pattern[strings.Index(pattern,"/"):]}url:=&url.URL{Path:path}mux.m[pattern[0:n-1]]=muxEntry{h:RedirectHandler(url.String(),StatusMovedPermanently),pattern:pattern}}}以上流程完成路由注册。②服务监听typeServerstruct{AddrstringHandlerHandlerReadTimeouttime.DurationWriteTimeouttime.DurationTLSConfig*tls.ConfigMaxHeaderBytesintTLSNextProtomap[string]func(*Server,*tls.Conn,Handler)ConnStatefunc(net.Conn,ConnState)ErrorLog*log.LoggerdisableKeepAlivesint32nextProtoOncesync.OncenextProtoErrerror}funcListenAndServe(addrstring,handlerHandler)error{server:=&Server{Addr:addr,Handler:handler}returnserver.ListenAndServe()}//初始化监听地址Addr,调用Listen方法设置监听。//***将监听的TCP对象传入Serve方法:func(srv*Server)ListenAndServe()error{addr:=srv.Addrifaddr==""{addr=":http"}ln,err:=net.Listen("tcp",addr)iferr!=nil{returnerr}returnsrv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}Serve(lnet.Listener)为每个请求开启goroutine设计,保证高并发性。func(srv*Server)Serve(lnet.Listener)error{deferl.Close()iffn:=testHookServerServe;fn!=nil{fn(srv,l)}vartempDelaytime.Duration//howlongtosleeponacceptfailureiferr:=srv.setupHTTP2_Serve();err!=nil{returnerr}srv.trackListener(l,true)defersrv.trackListener(l,false)baseCtx:=context.Background()//baseisalwaysbackground,perIssue16220ctx:=context.WithValue(baseCtx,ServerContextKey,srv)ctx=context.WithValue(ctx,LocalAddrContextKey,l.Addr())//开环监听for{//使用Listener的Accept方法获取连接数据rw,e:=l.Accept()ife!=nil{select{case<-srv.getDoneChan():returnErrServerCloseddefault:}ifne,ok:=e.(net.Error);ok&&ne.Temporary(){iftempDelay==0{tempDelay=5*time.Millisecond}else{tempDelay*=2}ifmax:=1*time.Second;tempDelay>max{tempDelay=max}srv.logf("http:Accepterror:%v;retryingin%v",e,tempDelay)time.Sleep(tempDelay)continue}return}tempDelay=0//通过获取的连接数据创建newConn连接对象c:=srv.newConn(rw)c.setState(c.rwc,StateNew)//beforeServecanreturn//开启goroutine发送连接请求goc.serve(ctx)}}serve()是核心,读取对应的连接数据进行分发func(c*conn)serve(ctxcontext.Context){c.remoteAddr=c.rwc.RemoteAddr().String()//连接关闭相关处理deferfunc(){iferr:=recover();err!=nil&&err!=ErrAbortHandler{constsize=64<<10buf:=make([]byte,size)buf=buf[:runtime.Stack(buf,false)]c.server.logf("http:panicserving%v:%v\n%s",c.remoteAddr,err,buf)}if!c.hijacked(){c.close()c.setState(c.rwc,StateClosed)}}().....ctx,cancelCtx:=context.WithCancel(ctx)c.cancelCtx=cancelCtxdefercancelCtx()c.r=&connReader{conn:c}c.bufr=newBufioReader(c.r)c.bufw=newBufioWriterSize(checkConnErrorWriter{c},4<<10)for{//读取客户端的请求w,err:=c.readRequest(ctx)ifc.r.remain!=c.server.initialReadLimitSize(){//Ifwereadanybytesoffthewire,we'reactive.c.setState(c.rwc,StateActive)}.........//Processingthestateofnetworkdata//Expect100Continuesupportreq:=w.reqifreq.expectsContinue(){ifreq.ProtoAtLeast(1,1)&&req.ContentLength!=0{//包裹eBodyreaderwithonethatrepliesontheconnectionreq.Body=&expectContinueReader{readCloser:req.Body,resp:w}}}elseifreq.Header.get("Expect")!=""{w.sendExpectationFailed()return}c.curReq.Store(w)ifrequestBodyRemains(req.Body){registerOnHitEOF(req.Body,w.conn.r.startBackgroundRead)}else{ifw.conn.bufr.Buffered()>0{w.conn.r.closeNotifyFromPipelinedRequest()}w.conn.r.startBackgroundRead()}//调用serverHandler{c.server}.ServeHTTP(w,w.req)//方法处理请求serverHandler{c.server}.ServeHTTP(w,w.req)w.cancelCtx()ifc.hijacked(){return}w.finishRequest()if!w.shouldReuseConnection(){ifw.requestBodyLimitHit||w.closedRequestBodyEarly(){c.closeWriteAndWait()}return}c.setState(c.rwc,StateIdle)c.curReq.Store((*response)(nil))if!w.conn.server.doKeepAlives(){return}ifd:=c.server.idleTimeout();d!=0{c.rwc.SetReadDeadline(time.Now().Add(d))if_,err:=c.bufr.Peek(4);err!=nil{return}}c.rwc.SetReadDeadline(time.Time{})}}③处理请求并返回结果serverHandlerMain初始化路由多路复用器如果服务器对象没有指定一个Handler,默认使用DefaultServeMux作为路由多路复用器。并调用初始化处理程序的ServeHTTP方法。typeserverHandlerstruct{srv*Server}func(shserverHandler)ServeHTTP(rwResponseWriter,req*Request){handler:=sh.srv.Handlerifhandler==nil{handler=DefaultServeMux}ifreq.RequestURI="*"&&req.Method="OPTIONS"{handler=globalOptionsHandler{}}handler.ServeHTTP(rw,req)}这里是前面提到的匹配路由的具体代码func(mux*ServeMux)ServeHTTP(wResponseWriter,r*Request){ifr.RequestURI=="*"{ifr.ProtoAtLeast(1,1){w.Header().Set("Connection","close")}w.WriteHeader(StatusBadRequest)return}//匹配路由上注册的处理函数h,_:=mux.Handler(r)//调用handler函数的ServeHTTP方法//即Hello函数,然后将数据写入http.ResponseWriter//对象返回给客户端。h.ServeHTTP(w,r)}func(mux*ServeMux)Handler(r*Request)(hHandler,patternstring){ifr.Method!="CONNECT"{ifp:=cleanPath(r.URL.Path);p!=r.URL.Path{_,pattern=mux.handler(r.Host,p)url:=*r.URLurl.Path=preturnRedirectHandler(url.String(),StatusMovedPermanently),pattern}}returnmux.handler(r.Host,r.URL.Path)}func(mux*ServeMux)handler(host,pathstring)(hHandler,patternstring){mux.mu.RLock()defermux.mu.RUnlock()//Host-specificpattern优先overgeneronesifmux.hosts{//比如127.0.0.1/helloh,pattern=mux.match(host+path)}ifh==nil{//比如/helloh,pattern=mux.match(path)}ifh==nil{h,pattern=NotFoundHandler(),""}return}func(mux*ServeMux)match(pathstring)(hHandler,patternstring){varn=0fork,v:=rangemux.m{if!pathMatch(k,path)}{continue}//通过迭代m找出注册的route//handler函数匹配实际url的patten模式并返回。ifh==nil||len(k)>n{n=len(k)h=v.hpattern=v.pattern}}return}funcpathMatch(pattern,pathstring)bool{iflen(pattern)==0{//shouldnothappenreturnfalse}n:=len(pattern)//注册pattern与请求uri相同则返回true,否则返回falseifpattern[n-1]!='/'{returnpattern==path}//静态文件匹配returnlen(path)>=n&&path[0:n]==pattern}向客户端写入数据//主代码,层层封装才走到这一步func(wcheckConnErrorWriter)Write(p[]byte)(nint,errerror){n,err=w.c.rwc.Write(p)iferr!=nil&&w.c.werr==nil{w.c.werr=errw.c.cancelCtx()}return}serverHandler{c.server}.ServeHTTP(w,w.req)当request结束后,开始执行连接断开的相关逻辑。总结Go语言通过ServeMux实现的路由多路复用器来管理路由。同时提供了一个Handler接口,提供ServeHTTP方法,实现了handler接口的功能,可以处理实际的请求并返回响应。ServeMux和处理函数之间的连接桥梁是Handler接口。ServeMux的ServeHTTP方法实现查找注册路由的handler的功能,调用handler的ServeHTTP方法。所以Handler接口是一个重要的枢纽。简单梳理一下整个请求响应流程,如下图
