How the Web works for Go

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed. Use it in go and its simple code to open a Web service. As follows:
test(){    http.HandleFunc("/", sayHello)    err := http.ListenAndServe(":9090",nil)    if err!=nil {        log.Fatal("ListenAndServer:",err)    }}func sayHello(w http.ResponseWriter, r *http.Request){    r.ParseForm()    fmt.Println("path",r.URL.Path)    fmt.Println("scheme",r.URL.Scheme)    fmt.Fprintf"Hello Guest!")}

When using ListenAndServe this method, the system assigns us a router, which is the default router used by the system DefaultServeMux , and if the ListenAndServe 2nd parameter of this method is passed to nil, the system will be used by default DefaultServeMux . Of course, you can also pass in a custom router here.

First look http.HandleFunc("/", sayHello) , from the HandleFunc method point, as follows:

func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    DefaultServeMux.HandleFunc(pattern, handler)}

The method called here DefaultServeMux HandleFunc , which has two parameters, pattern is a matching routing rule that handler represents the corresponding processing method for the routing rule, and the processing method has two parameters.

In the code example we write, the corresponding, pattern / handler corresponding sayHello , when we enter in the browser http://localhost:9090 , the method is triggered sayHello .

We DefaultServeMux will continue to follow the HandleFunc method, as follows:

func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {    mux.Handle(pattern, HandlerFunc(handler))}

In this method, the router calls the Handle method and takes note Handle of the 2nd parameter of the method, forcing the previously passed response method to be cast to the handler HandlerFunc type.

HandlerFuncWhat exactly is this type of thing? As follows:

type HandlerFunc func(ResponseWriter, *Request)

It seems that the types of methods we define SayHello are similar. But!!!
This HandlerFunc default implements the ServeHTTP interface! So HandlerFunc the object has a ServeHTTP way! As follows:

// ServeHTTP calls f(w, r).func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {    f(w, r)}

This detail is important because this step concerns the question of whether the corresponding response method will be called when the routing rule matches! The invocation of this method is referred to in the next section.

Next, we'll go back to the way we're going to see mux Handle it, that's the code mux.Handle(pattern, HandlerFunc(handler)) . What does this piece of code do? The source code is as follows:

Func (Mux *servemux) Handle (pattern string, handler handler) {Mux.mu.Lock () defer mux.mu.Unlock ()ifPattern = =""{Panic ("Http:invalid pattern"+ pattern)}ifHandler = = Nil {Panic ("Http:nil handler")    }ifmux.m[pattern].explicit {Panic ("Http:multiple registrations for"+ pattern)}ifMUX.M = = Nil {mux.m = make (Map[string]muxentry)} Mux.m[pattern] = muxentry{explicit:true, H:handler, Pattern:pattern}ifPATTERN[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)ifn > 0 && pattern[n-1] = ='/'&&!mux.m[pattern[0:n-1]].explicit {//If pattern contains a host name, strip it and use remaining Path forredirect. Path: = PatternifPATTERN[0]! ='/'{//in pattern, at least the last character is a'/', so//strings. Index can' t be-1. Path = pattern[strings. Index (Pattern, "/"):]} URL: = &url. Url{path:path} mux.m[pattern[0:n-1]] = Muxentry{h:redirecthandler (URL. String (), statusmovedpermanently), Pattern:pattern} }}

Code is very much, in fact, the main thing to do is to DefaultServeMux map[string]muxEntry increase the corresponding routing rules and handler .

map[string]muxEntryWhat kind of a ghost?

mapis a Dictionary object that holds the key-value .
[string]Indicates that the dictionary key is of string type, and this key value will save our routing rules.
muxEntryis an instance object that holds the corresponding processing method for the routing rule.

Find the appropriate code, as follows:

//路由器type ServeMux struct {    mu    sync.RWMutex    m     map[string]muxEntry //路由规则,一个string对应一个mux实例对象,map的key就是注册的路由表达式(string类型的)    hosts bool // whether any patterns contain hostnames}//muxEntrytype muxEntry struct {    explicit bool    h        Handler //这个路由表达式对应哪个handler    pattern  string}//路由响应方法type Handler interface {    ServeHTTP(ResponseWriter, *Request)  //handler的路由实现器}

ServeMuxis the default router for this system.

Finally, summarize this section:
1. Callhttp.HandleFunc("/", sayHello)
2. Call DefaultServeMux HandleFunc() , put our definition of sayHello() packaging into a HandlerFunc type
3. Continue the DefaultServeMux call Handle() , DefaultServeMux add the map[string]muxEntry routing rules to the, and the correspondinghandler

OK, this part of the code is doing so much, the first part ends.

The second part is mainly to study this code, that is err := http.ListenAndServe(":9090",nil) , ListenAndServe this method. From this method point in, as follows:

func ListenAndServe(addr string, handler Handler) error {    server := &Server{Addr: addr, Handler: handler}    return server.ListenAndServe()}

In this method, an object is initialized, server and then the method of invoking the server object, ListenAndServe in this method, is as follows:

func (srv *Server) ListenAndServe() error {    addr := srv.Addr    if"" {        ":http"    }    ln, err := net.Listen("tcp", addr)    if err != nil {        return err    }    return srv.Serve(tcpKeepAliveListener{ln.(*net.TCPListener)})}

In this method, a call is made, that is, the net.Listen("tcp", addr) underlying TCP protocol is used to build a service and then monitor the ports we set up.

At the end of the code, the srv method called is Serve as follows:

Func (SRV *server) Serve (l net. Listener) Error {defer l.close ()iffn: =TestHookserverserve; fn! = Nil {fn (SRV, L)} var tempdelay time. Duration//How long-to-sleep on accept failureifERR: = Srv.setuphttp2_serve (); Err! = Nil {returnERR} srv.tracklistener (L,true) Defer Srv.tracklistener (L,false) Basectx: = Context. Background ()//base is always Background, per Issue 16220 CTX: = context. Withvalue (Basectx, Servercontextkey, srv) CTX = context. Withvalue (CTX, Localaddrcontextkey, L.addr ()) for{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:accept error:%v; Retrying in%v ", E, Tempdelay) time. Sleep (Tempdelay)Continue}returne} tempdelay = 0 c: = Srv.newconn (rw) c.setstate (C.RWC, statenew)//before Serve canreturnGo C.serve (CTX)}}

The last 3 pieces of code are more important and are the embodiment of the high concurrency of the Go Language support, as follows:

returngo c.serve(ctx)

Above that big piece of code, the general meaning is to enter the method, the first open a for loop, in the for loop time accept request, after the request comes, will create one for each request, Conn and then open a separate goroutine , the request data as parameters thrown to this Conngo to service: go c.serve() . Each request of the user is in a new goroutine go service, and each request does not affect each other.

In conn the serve method, there is a code that is important, as follows:

serverHandler{c.server}.ServeHTTP(w, w.req)

SaidserverHandler

Also

Implementation of the ServeHTTP interface, the ServeHTTP method is implemented as follows:

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {    handler := sh.srv.Handler    if handler == nil {        handler = DefaultServeMux    }    if"*""OPTIONS" {        handler = globalOptionsHandler{}    }    handler.ServeHTTP(rw, req)}

Here if it is handler empty (this handler can be understood as our custom router), we will use the system default DefaultServeMux , the last Call of the code DefaultServeMuxServeHTTP()

func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request) {    if"*" {        if r.ProtoAtLeast(1, 1) {            w.Header().Set("Connection""close")        }        w.WriteHeader(StatusBadRequest)        return    }    h, _ := mux.Handler(r)  //这里返回的h是Handler接口对象    h.ServeHTTP(w, r)       //调用Handler接口对象的ServeHTTP方法实际上就调用了我们定义的sayHello方法}

After the router receives the request, if it is * then close the link, if it is not * called to mux.Handler(r) return the route corresponding to the processing Handler , and then execute the method, that is, handler ServeHTTP This code h.ServeHTTP(w, r) , mux.Handler(r) do what? As follows:

Func (Mux *servemux) Handler (R *request) (H Handler, pattern string) {ifR.method! ="CONNECT"{ifP: = CleanPath (R.url. Path); P! = R.url. Path {_, pattern = Mux.handler (r.host, p) URL: = *r.url URL. Path = PreturnRedirecthandler (URL. String (), statusmovedpermanently), pattern}}returnMux.handler (R.host, R.url. Path)}func (Mux *servemux) handler (host, path string) (H handler, pattern string) {Mux.mu.RLock () defer MUX.MU.RUNL Ock ()//Host-specific pattern takes precedence over generic onesifmux.hosts {h, pattern = mux.match (host + Path)}ifH = = Nil {h, pattern = Mux.match (path)}ifH = = Nil {h, pattern = Notfoundhandler (),""}return}func (Mux *servemux) match (Path string) (H Handler, pattern string) {var n = 0 forK, V: = Range mux.m {//MUX.M is the map of the system default routeif!pathmatch (k, path) {Continue}ifH = = Nil | | Len (k) > N {n = len (k) h = v.h pattern = V.pattern}}return}

It matches the map stored in the router according to the user's requested URL , and the matching succeeds returns the stored handler , calling this handler The 's servehttp () can be executed to the appropriate processing method, which is actually the SayHello () that we just started to define, except this SayHello ( is handlerfunc is wrapped again because Handlerfunc implements the servehttp interface, so the call Handlerfunc object's servehttp () , our SayHello () is actually called inside of servehttp () .

Summarize:
1. Call http. Listenandserve (": 9090", nil)
2. Instantiate the server
3. Call server , Listenandserve ()
4. Call the Serve method of server to turn on the for Loop and accept the request in the Loop
5. Instantiate a single request for each Conn , and open a goroutine service for this request go C.serve ()
6. Read the contents of each request C.readrequest ()
7. Call servehttp () for Serverhandler , and if handler is empty, handler is set to the system default router Defaultservemux
8. Call handler servehttp () = = actually called defaultservemux servehttp ()
9. In servehttp () The route handling handler
10. In route correspondence processing Handler executes SayHello ()

There is one point to note:
DefaultServeMuxand the route corresponding to the processing methods handler are implemented ServeHTTP interface, they both have ServeHTTP methods, but the method to achieve the purpose of different, in DefaultServeMux the implementation of the ServeHttp() route corresponding handler processing ServeHttp() .


Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.