This is a creation in Article, where the information may have evolved or changed.
Golang HTTP's handle module (commonly referred to as the Hook module), this embedded function is easily implemented by anonymous functions in high-level languages handle
In general, we use Golang HTTP handlefunc to handle the server side of HTTP as appropriate
/*********************************************/http. Handlefunc ("/", xxx_fun) Err: = http. Listenandserve (": 8080", nil) if err! = Nil {log. Fatal ("Listenandserve:", err)}/*********************************************/
Let's go deep into the source code and take a closer look at http. The realization of Handlefunc
Func handlefunc (Pattern string, handler func (responsewriter, *request)) { Defaultservemux.handlefunc (Pattern, handler)}// newservemux allocates and returns a new servemux.var defaultservemux = newservemux () Func NewServeMux () *servemux { return &servemux{m: make (map[string]muxentry)} }type ServeMux struct {mu sync. rwmutex //A read-write lock m map[string]muxentry //Mapping of a path (patterns) maphosts bool // whether any patterns contain hostnames}
Take a look at the concrete implementation of Listenandserve
Func listenandserve (Addr string, handler handler) error {server := &server{addr: addr, handler: handler}return server. Listenandserve ()}func (srv *server) listenandserve () error {addr := srv. addrif addr == "" {addr = ": http"}ln, err := net. Listen ("TCP", addr) if err != nil {return err}return srv. Serve (Tcpkeepalivelistener{ln. ( *net. TcpListener)})}// serve accepts incoming connections on the listener l , creating a// new service goroutine for each. the service goroutines read requests and// then call srv. handler to reply to them.func (Srv *server) serve (l net. Listener) error {defer l.close () var tempdelay time. Duration //&nBsp;how long to sleep on accept failurefor {rw, e := l. Accept () if e != nil {if ne, ok := e. (NET. Error); ok && ne. Temporary () {if tempdelay == 0 {tempdelay = 5 * time. Millisecond} else {tempdelay *= 2}if max := 1 * time. SECOND; TEMPDELAY > MAX {TEMPDELAY = MAX}SRV.LOGF ("http: Accept Error: %v; retrying in %v ", e, tempdelay) time. Sleep (Tempdelay) continue}return e}tempdelay = 0c, err := srv.newconn (rw) if Err != nil {continue}c.setstate (c.rwc, statenew) // before serve can returngo c.serve () //It seems that this c.serve is the processing entrance}}
It appears that this c.serve is a processing portal
Serve a new connection.func (C *conn) serve () {origconn := c.rwc // copy it before it ' s set nil on close or Hijackdefer func () {if err := recover (); err != nil {const Size = 64 << 10buf := make ([]byte, size) buf = buf[:runtime. Stack (Buf, false)]c.server.logf ("http: panic serving %v: %v\n%s", c.remoteAddr, &NBSP;ERR,&NBSP;BUF)}if !c.hijacked () {c.close () c.setstate (origconn, stateclosed)}} () if TLSCONN,&NBSP;OK&NBSP;:=&NBSP;C.RWC. (*tls. Conn); ok {if d := c.server.readtimeout; d != 0 { C.rwc.setreaddeadline (time. Now (). ADD (d))}if d := c.server.writetimeout; d != 0 {c.rwc.setwritedeadline (time. Now (). ADD (d))}if err := tlsconn.handshake (); err ! =&NBSP;NIL&NBSP;{C.SERVER.LOGF ("Http: tls handshake error from %s: %v", C.rwc.remoteaddr (), err) return}c.tlsstate = new (TLS. ConnectionState) *c.tlsstate = tlsconn.connectionstate () if proto := C.TLSSTATE.NEGOTIATEDPROTOCOL;&NBSP;VALIDNPN (proto) {if fn := c.server.tlsnextproto[proto] ; &NBSP;FN&NBSP;!=&NBSP;NIL&NBSP;{H&NBSP;:=&NBSP;INITNPNREQUEST{TLSCONN,&NBSP;SERVERHANDLER{C.SERVER}}FN ( C.SERVER,&NBSP;TLSCONN,&NBSP;H)}return}}for {w, err := c.readrequest () if c.lr.N != c.server.initiallimitedreadersize () {// if we read any bytes off the wire, we ' Re active.c.setstate (c.rwc, stateactive)}if err != nil {if err == errTooLarge {// Their HTTP client may or May not be// able to read this if we ' re// responding to them and hanging up// while they ' re still Writing their// request. undefined behavior.io.writestring (c.rwc, "HTTP/1.1 413 request entity too large\r\n\r\n ") c.closewriteandwait () break} else if err == io. Eof {break // don ' T reply} else if neterr, ok := err. (NET. Error); ok && neterr. Timeout () {break // don ' T reply}io. WriteString (c.rwc, "http/1.1 400 bad request\r\n\r\n") break}// expect 100 Continue supportreq := w.reqif req.expectscontinue () {if req. Protoatleast (1, 1) && req. Contentlength != 0 {// wrap the body reader with one that replies on the connectionreq. Body = &expectcontinuereaDer{readcloser: req. Body, resp: w}}req. Header.del ("Expect")} else if req. Header.get ("Expect") != "" {w.sendexpectationfailed () Break}// http cannot have multiple simultaneous active requests. [*]// until the server replies to this request, it can ' t read another,// so we might as well run the handler in This goroutine.// [*] not strictly true: http pipelining. we could let them all process// in parallel even if their responses need to be serialized.serverhandler{c.server}. Servehttp (w, w.req) //This is the entrance if c.hijacked () {return}w.finishrequest () if W.closeafterreply {if w.requestbodylimithit {c.closewriteandwait ()}break}c.setState (C.RWC, stateidle)}}
The
Handler processing entry is Serverhandler{c.server}. Serverhttp (W,w.req), final to Handlefunc execution
func (Mux *servemux) handler (r *request) (h handler, pattern string) {if r.Method != "CONNECT" {if p := cleanpath (R.url. Path); p != r.url. Path {_, pattern = mux.handler (r.host, p) //Next process Url := *r.urlurl.path = preturn redirecthandler (URL. String (), statusmovedpermanently), pattern}}return mux.handler (R.host, r.url. Path) //Next process}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 (), "" //returns the default anonymous function if the handler corresponding anonymous function is empty}return}// 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) //next deals with H. Servehttp (w, r) //next processes}//the next action func (MUX&NBSP;*SERVEMUX) handlefunc (pattern String, handler func (responsewriter, *request)) {mux. Handle (Pattern, handlerfunc (handler))}func (mux *seRvemux) handle (pattern string, handler handler) { //processing patternmux.mu.Lock () Defer mux.mu.unlock () if pattern == "" {panic ("http: invalid pattern " + pattern)}if handler == nil {panic ("Http: nil handler")}if Mux.m[pattern].explicit {panic ("http: multiple registrations for " + pattern)}mux.m[pattern] = muxentry{explicit: true, h: handler, pattern: pattern} //set Servemux's mapif pattern[0] != '/' {mux.hosts = true}// helpful behavior:// if pattern is /tree/, insert an implicit permanent redirect for /tree.// it can be overridden by an Explicit registration.n := len (pattern) if n > 0 && pattern[ n-1] == '/' && !mux.m[pattern[0:n-1]].explicit {// If pattern contains a host name, strip it and use remaining// path for redirect.path := patternif pattern[0] != '/' {// in pattern, at least the last character is a '/', so// strings. Index can ' T be -1.path = pattern[strings. Index (pattern, "/"):]}mux.m[pattern[0:n-1]] = muxentry{h: redirecthandler (path, statusmovedpermanently), pattern: pattern}}}
Finally, take a look at the operation of the corresponding map with a MUX match:
Func (Mux *servemux) match (Path string) (H Handler, pattern string) {var n = 0for k, V: = Range mux.m {if!pathmatch (K, PA TH) {//Match continue}if H = = Nil | | Len (k) > N {n = len (k) h = V.hpattern = V.pattern}}return}