HTTP server,顾名思义,支持http协议的服务器,HTTP是一个简单的请求-响应协议,通常运行在TCP之上。通过客户端发送请求给服务器得到对应的响应。
Go语言中HTTP Server:
HTTP server,顾名思义,支持http协议的服务器,HTTP是一个简单的请求-响应协议,通常运行在TCP之上。通过客户端发送请求给服务器得到对应的响应。
HTTP服务简单实现
- packagemain
- import(
- "fmt"
- "net/http"
- )
- //③处理请求,返回结果
- funcHello(whttp.ResponseWriter,r*http.Request){
- fmt.Fprintln(w,"helloworld")
- }
- funcmain(){
- //①路由注册
- http.HandleFunc("/",Hello)
- //②服务监听
- http.ListenAndServe(":8080",nil)
- }
[[188005]]
你以为这样就结束了吗,不才刚刚开始。
①路由注册
- funcHandleFunc(patternstring,handlerfunc(ResponseWriter,*Request)){
- DefaultServeMux.HandleFunc(pattern,handler)
- }
DefaultServeMux是什么?
DefaultServeMux是ServeMux的一个实例。
ServeMux又是什么?
- //DefaultServeMuxisthedefaultServeMuxusedbyServe.
- varDefaultServeMux=&defaultServeMux
- vardefaultServeMuxServeMux
- typeServeMuxstruct{
- musync.RWMutex
- mmap[string]muxEntry
- hostsbool
- }
- typemuxEntrystruct{
- explicitbool
- hHandler
- patternstring
- }
ServeMux主要通过map[string]muxEntry,来存储了具体的url模式和handler(此handler是实现Handler接口的类型)。通过实现Handler的ServeHTTP方法,来匹配路由(这一点下面源码会讲到)
很多地方都涉及到了Handler,那么Handler是什么?
- typeHandlerinterface{
- ServeHTTP(ResponseWriter,*Request)
- }
此接口可以算是HTTP Server一个枢纽
- func(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的Handle方法:
- 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和pattern模式绑定到
- //map[string]muxEntry的map上
- mux.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:=pattern
- ifpattern[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{
- Addrstring
- HandlerHandler
- ReadTimeouttime.Duration
- WriteTimeouttime.Duration
- TLSConfig*tls.Config
- MaxHeaderBytesint
- TLSNextProtomap[string]func(*Server,*tls.Conn,Handler)
- ConnStatefunc(net.Conn,ConnState)
- ErrorLog*log.Logger
- disableKeepAlivesint32nextProtoOncesync.Once
- nextProtoErrerror
- }
- funcListenAndServe(addrstring,handlerHandler)error{
- server:=&Server{Addr:addr,Handler:handler}
- returnserver.ListenAndServe()
- }
- //初始化监听地址Addr,同时调用Listen方法设置监听。
- //***将监听的TCP对象传入Serve方法:
- 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)})
- }
Serve(l net.Listener)为每个请求开启goroutine的设计,保证了go的高并发。
- func(srv*Server)Serve(lnet.Listener)error{
- deferl.Close()
- iffn:=testHookServerServe;fn!=nil{
- fn(srv,l)
- }
- vartempDelaytime.Duration//howlongtosleeponacceptfailure
- iferr:=srv.setupHTTP2_Serve();err!=nil{
- returnerr
- }
- srv.trackListener(l,true)
- defersrv.trackListener(l,false)
- baseCtx:=context.Background()//baseisalwaysbackground,perIssue16220
- ctx:=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():
- returnErrServerClosed
- default:
- }
- 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
- //通过获得的连接数据,创建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<<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(c.rwc,StateClosed)
- }
- }()
- .....
- ctx,cancelCtx:=context.WithCancel(ctx)
- c.cancelCtx=cancelCtx
- defercancelCtx()
- 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)
- }
- .................
- //处理网络数据的状态
- //Expect100Continuesupport
- req:=w.req
- ifreq.expectsContinue(){
- ifreq.ProtoAtLeast(1,1)&&req.ContentLength!=0{
- //WraptheBodyreaderwithonethatrepliesontheconnection
- req.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{})
- }
- }
③处理请求,返回结果
serverHandler 主要初始化路由多路复用器。如果server对象没有指定Handler,则使用默认的DefaultServeMux作为路由多路复用器。并调用初始化Handler的ServeHTTP方法。
- typeserverHandlerstruct{
- srv*Server
- }
- func(shserverHandler)ServeHTTP(rwResponseWriter,req*Request){
- handler:=sh.srv.Handler
- ifhandler==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
- }
- //匹配注册到路由上的handler函数
- 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.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{
- //如127.0.0.1/hello
- h,pattern=mux.match(host+path)
- }
- ifh==nil{
- //如/hello
- h,pattern=mux.match(path)
- }
- ifh==nil{
- h,pattern=NotFoundHandler(),""
- }
- return
- }
- func(mux*ServeMux)match(pathstring)(hHandler,patternstring){
- varn=0
- fork,v:=rangemux.m{
- if!pathMatch(k,path){
- continue
- }
- //通过迭代m寻找出注册路由的patten模式
- //与实际url匹配的handler函数并返回。
- ifh==nil||len(k)>n{
- n=len(k)
- h=v.h
- pattern=v.pattern
- }
- }
- return
- }
- funcpathMatch(pattern,pathstring)bool{
- iflen(pattern)==0{
- //shouldnothappen
- returnfalse
- }
- n:=len(pattern)
- //如果注册模式与请求uri一样返回true,否则false
- ifpattern[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=err
- w.c.cancelCtx()
- }
- return
- }
serverHandler{c.server}.ServeHTTP(w, w.req)当请求结束后,就开始执行连接断开的相关逻辑。
总结
Go语言通过一个ServeMux实现了的路由多路复用器来管理路由。同时提供一个Handler接口提供ServeHTTP方法,实现handler接口的函数,可以处理实际request并返回response。
ServeMux和handler函数的连接桥梁就是Handler接口。ServeMux的ServeHTTP方法实现了寻找注册路由的handler的函数,并调用该handler的ServeHTTP方法。
所以说Handler接口是一个重要枢纽。
简单梳理下整个请求响应过程,如下图
©本文为清一色官方代发,观点仅代表作者本人,与清一色无关。清一色对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。本文不作为投资理财建议,请读者仅作参考,并请自行承担全部责任。文中部分文字/图片/视频/音频等来源于网络,如侵犯到著作权人的权利,请与我们联系(微信/QQ:1074760229)。转载请注明出处:清一色财经