golang http的handle模块(一般也称为钩子模块),通过高级语言的匿名函数很容易实现这种内嵌功能的handle
我们一般这样使用golang的http HandleFunc来为http的server端做相应的处理
/*********************************************/ http.HandleFunc("/",xxx_FUN) err:=http.ListenAndServe(":8080",nil) iferr!=nil{ log.Fatal("ListenAndServe:",err) } /*********************************************/
我们再深入源码仔细看看http.HandleFunc的实现
funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){ DefaultServeMux.HandleFunc(pattern,handler) } //NewServeMuxallocatesandreturnsanewServeMux. varDefaultServeMux=NewServeMux() funcNewServeMux()*ServeMux{return&ServeMux{m:make(map[string]muxEntry)}} typeServeMuxstruct{ musync.RWMutex//一个读写锁 mmap[string]muxEntry//一个path(patterns)的映射map hostsbool//whetheranypatternscontainhostnames }
再来看看ListenAndServe的具体实现
funcListenAndServe(addrstring,handlerHandler)error{ server:=&Server{Addr:addr,Handler:handler} returnserver.ListenAndServe() } func(srv*Server)ListenAndServe()error{ addr:=srv.Addr ifaddr==""{ addr=":http" } ln,err:=net.Listen("tcp",addr) iferr!=nil{ returnerr } returnsrv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)}) } //ServeacceptsincomingconnectionsontheListenerl,creatinga //newservicegoroutineforeach.Theservicegoroutinesreadrequestsand //thencallsrv.Handlertoreplytothem. func(srv*Server)Serve(lnet.Listener)error{ deferl.Close() vartempDelaytime.Duration//howlongtosleeponacceptfailure for{ rw,e:=l.Accept() ife!=nil{ 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 } returne } tempDelay=0 c,err:=srv.newConn(rw) iferr!=nil{ continue } c.setState(c.rwc,StateNew)//beforeServecanreturn goc.serve()//看来这个c.serve是处理的入口 } }
看来这个c.serve是处理的入口
//Serveanewconnection. func(c*conn)serve(){ origConn:=c.rwc//copyitbeforeit'ssetnilonCloSEOrHijack deferfunc(){ iferr:=recover();err!=nil{ constsize=64<<10 buf:=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(origConn,StateClosed) } }() iftlsConn,ok:=c.rwc.(*tls.Conn);ok{ ifd:=c.server.ReadTimeout;d!=0{ c.rwc.SetReadDeadline(time.Now().Add(d)) } ifd:=c.server.WriteTimeout;d!=0{ c.rwc.SetWriteDeadline(time.Now().Add(d)) } iferr:=tlsConn.Handshake();err!=nil{ c.server.logf("http:TLShandshakeerrorfrom%s:%v",c.rwc.RemoteAddr(),err) return } c.tlsState=new(tls.ConnectionState) *c.tlsState=tlsConn.ConnectionState() ifproto:=c.tlsState.NegotiatedProtocol;validNPN(proto){ iffn:=c.server.TLSNextProto[proto];fn!=nil{ h:=initNPNRequest{tlsConn,serverHandler{c.server}} fn(c.server,tlsConn,h) } return } } for{ w,err:=c.readRequest() ifc.lr.N!=c.server.initialLimitedReaderSize(){ //Ifwereadanybytesoffthewire,we'reactive. c.setState(c.rwc,StateActive) } iferr!=nil{ iferr==errTooLarge{ //TheirHTTPclientmayormaynotbe //abletoreadthisifwe're //respondingtothemandhangingup //whilethey'restillwritingtheir //request.Undefinedbehavior. io.WriteString(c.rwc,"HTTP/1.1413RequestEntityTooLarge\r\n\r\n") c.closeWriteAndWait() break }elseiferr==io.EOF{ break//Don'treply }elseifneterr,ok:=err.(net.Error);ok&&neterr.Timeout(){ break//Don'treply } io.WriteString(c.rwc,"HTTP/1.1400BadRequest\r\n\r\n") break } //Expect100Continuesupport req:=w.req ifreq.expectsContinue(){ ifreq.ProtoAtLeast(1,1)&&req.ContentLength!=0{ //WraptheBodyreaderwithonethatrepliesontheconnection req.Body=&expectContinueReader{readCloser:req.Body,resp:w} } req.Header.Del("Expect") }elseifreq.Header.get("Expect")!=""{ w.sendExpectationFailed() break } //HTTPcannothavemultiplesimultaneousactiverequests.[*] //Untiltheserverrepliestothisrequest,itcan'treadanother,//sowemightaswellrunthehandlerinthisgoroutine. //[*]Notstrictlytrue:HTTPpipelining.Wecouldletthemallprocess //inparalleleveniftheirresponsesneedtobeserialized. serverHandler{c.server}.ServeHTTP(w,w.req)//这个是入口 ifc.hijacked(){ return } w.finishRequest() ifw.closeAfterReply{ ifw.requestBodyLimitHit{ c.closeWriteAndWait() } break } c.setState(c.rwc,StateIdle) } }
Handler处理的入口就是serverHandler{c.server}.ServerHTTP(w,w.req),最终到HandleFunc的执行
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.URL url.Path=p returnRedirectHandler(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-specificpatterntakesprecedenceovergenericones ifmux.hosts{ h,pattern=mux.match(host+path) } ifh==nil{ h,pattern=mux.match(path) } ifh==nil{ h,pattern=NotFoundHandler(),""//如果handler对应的匿名函数为空,则返回默认的匿名函数 } return } //ServeHTTPdispatchestherequesttothehandlerwhose //patternmostcloselymatchestherequestURL. 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)//接下来处理 h.ServeHTTP(w,r)//接下来处理 } //接下来就初始时候执行的操作 func(mux*ServeMux)HandleFunc(patternstring,*Request)){ mux.Handle(pattern,HandlerFunc(handler)) } func(mux*ServeMux)Handle(patternstring,handlerHandler){//处理pattern mux.mu.Lock() defermux.mu.Unlock() ifpattern==""{ panic("http:invalidpattern"+pattern) } ifhandler==nil{ panic("http:nilhandler") } ifmux.m[pattern].explicit{ panic("http:multipleregistrationsfor"+pattern) } mux.m[pattern]=muxEntry{explicit:true,h:handler,pattern:pattern}//设置ServeMux的map ifpattern[0]!='/'{ mux.hosts=true } //Helpfulbehavior: //Ifpatternis/tree/,insertanimplicitpermanentredirectfor/tree. //Itcanbeoverriddenbyanexplicitregistration. n:=len(pattern) ifn>0&&pattern[n-1]=='/'&&!mux.m[pattern[0:n-1]].explicit{ //Ifpatterncontainsahostname,stripitanduseremaining //pathforredirect. path:=pattern ifpattern[0]!='/'{ //Inpattern,atleastthelastcharacterisa'/',so //strings.Indexcan'tbe-1. path=pattern[strings.Index(pattern,"/"):] } mux.m[pattern[0:n-1]]=muxEntry{h:RedirectHandler(path,pattern:pattern} } }
最后再看看通过mux匹配获取对应的map的操作:
func(mux*ServeMux)match(pathstring)(hHandler,patternstring){ varn=0 fork,v:=rangemux.m{ if!pathMatch(k,path){//匹配 continue } ifh==nil||len(k)>n{ n=len(k) h=v.h pattern=v.pattern } } return }