Golang HTTP Packet default route matching rules read notes

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

First, the implementation process

To build a simple HTTP server:

package mainimport (    "log"    "net/http")func main() {    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        w.Write([]byte("hello world"))    })    log.Fatal(http.ListenAndServe(":8080", nil))}

Use http://127.0.0.1:8080/ to see the output

By tracing the Http.go package code, you can see that the execution process is basically as follows:

1. Create a Listener listening 8080 port

2. Enter the for loop and accept the request, no request is in the blocking state

3. Receive the request and create a Conn object to put into the goroutine processing (for high concurrency critical)

4. Resolve the request source information to obtain the request path and other important information

5. Request the Serverhttp method, the Responsewriter and request objects have been obtained through the previous step

func (sh serverHandler) ServeHTTP(rw ResponseWriter, req *Request) {    //此handler即为http.ListenAndServe 中的第二个参数    handler := sh.srv.Handler     if handler == nil {        //如果handler为空则使用内部的DefaultServeMux 进行处理        handler = DefaultServeMux    }    if req.RequestURI == "*" && req.Method == "OPTIONS" {        handler = globalOptionsHandler{}    }    //这里就开始处理http请求    //如果需要使用自定义的mux,就需要实现ServeHTTP方法,即实现Handler接口。    handler.ServeHTTP(rw, req)}

6. The logic to enter the Defaultservemux is to match the lookup handler in the map with the request path and leave it to handler

HTTP request processing process for more information, refer to the [Go WEB programming
"3.3 Go how to make Web Work" (HTTPS://GITHUB.COM/ASTAXIE/BUILD-WEB-APPLICATION-WITH-GOLANG/BLOB/MASTER/ZH/03.3.MD)

Second, Defaultservemux routing matching rules

Let's look at a few routing rules:

package mainimport (    "log"    "net/http")func main() {    //规则1    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {        w.Write([]byte("hello world"))    })        //规则2    http.HandleFunc("/path/", func(w http.ResponseWriter, r *http.Request) {        w.Write([]byte("pattern path: /path/ "))    })    //规则3    http.HandleFunc("/path/subpath", func(w http.ResponseWriter, r *http.Request) {        w.Write([]byte("pattern path: /path/subpath"))    })    log.Fatal(http.ListenAndServe(":8080", nil))}

Scenario One:

Visit: http://127.0.0.1:8080/

Return:hello world

Scenario Two:

Visit: http://127.0.0.1:8080/path

Return:pattern path: /path/

Scenario Three:

Visit: http://127.0.0.1:8080/path/subpath/

Return:pattern path: /path/

Scenario Four:

Visit: http://127.0.0.1:8080/hahaha/

Return:hello world

Let's start by explaining some of the rules, and then see how the code is implemented:

1. If there is a match in the path / , it will automatically add a matching rule without / suffix, and jump to path/ , explain the scenario two scenarios, why match to the/path/

2. I set so many rules why is the rule one generic to match the routing information that is not set, and does not affect the existing route, how the internal implementation?

2.1 Adding a routing rule

Let's look at two structs, which are the default routing rules:

type ServeMux struct {    mu    sync.RWMutex  //处理并发,增加读写锁    m     map[string]muxEntry  //存放规则map,key即为设置的path    hosts bool // whether any patterns contain hostnames(是否包含host)}type muxEntry struct {    explicit bool //是否完全匹配    h        Handler//相应匹配规则的handler    pattern  string//匹配路径}

By tracking http.HandleFunc to the following code, it is to struct add the rule to the above two:

Func (Mux *servemux) Handle (pattern string, handler handler) {Mux.mu.Lock () defer mux.mu.Unlock () if pattern = =    "{Panic (" http:invalid pattern "+ pattern)} if handler = = nil {Panic (" Http:nil handler ")}        Panic if mux.m[pattern].explicit {panic ("Http:multiple registrations for" + pattern) if it is already matched}    Add a new matching rule mux.m[pattern] = Muxentry{explicit:true, H:handler, Pattern:pattern}//To determine if there is a host based on the first letter of Path If pattern[0]! = '/' {mux.hosts = true}//!! Here to see clearly is to achieve the situation of scenario two, see the conditions of the condition 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: = Pattern if pattern[0]! = '/' {//in pattern, at least the last character are 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}}}

There is a Helpful behavior comment on the behavior, is to achieve the situation of two situations, he is to determine if the matching path is finally contained / , and there is no previous rule to add the removal of the backslash, it will automatically give him a 301 jump point/path/

2.2 Finding routing rules

The search for routing rules is to match the lookup from the ServeMux map in, to this handler and execute, but there are some processing mechanisms, such as how to ensure that access /path/subpath is the first match /path/subpath rather than match /path/ it?

When a request comes in, the method is tracked mux.match :

Process mux.ServerHTTP , mux.Handler mux.handlermux.match

func (mux *ServeMux) match(path string) (h Handler, pattern string) {    var n = 0    for k, v := range mux.m {        if !pathMatch(k, path) {            continue        }        //如果匹配到了一个规则,并没有马上返回handler,而且继续匹配并且判断path的长度是否是最长的,这是关键!!!        if h == nil || len(k) > n {            n = len(k)            h = v.h            pattern = v.pattern        }    }    return}

1. This explains why the exact path set is the optimal match, as it is judged by the length of the path.
Of course it explains why / you can match all (see pathMatch function to know, / match all, just this is the last to be matched successfully)

2. Get the handler of processing request, and then call to h.ServeHTTP(w, r) execute the corresponding handler method.

Wait a minute, where in handler has ServeHTTP this method??

Since the http.HandleFunc custom handler handler has been coerced to type at the time of invocation HandlerFunc , it has the ServeHTTP method:

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

f(w,r)The implementation of the handler is realized.

Original address: silenceper.com

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.