• router


    1. router in golang

    1). sample code

     1 package main
     2 
     3 import (
     4     "fmt"
     5     "net/http"
     6 )
     7 
     8 func main() {
     9 
    10     http.HandleFunc("/handlefunc", func(w http.ResponseWriter, r *http.Request) {
    11         fmt.Fprintf(w, "http.HandleFunc")
    12     })
    13 
    14     http.Handle("/handle", &myHandler{})
    15 
    16     http.ListenAndServe(":8080", nil)
    17 }
    18 
    19 type myHandler struct{}
    20 
    21 func (this *myHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    22     fmt.Fprintf(w, "http.Handle")
    23 }

     2). implement

    a) top layer:

    // Objects implementing the Handler interface can be
    // registered to serve a particular path or subtree
    // in the HTTP server.
    //
    // ServeHTTP should write reply headers and data to the ResponseWriter
    // and then return.  Returning signals that the request is finished
    // and that the HTTP server can move on to the next request on
    // the connection.
    type Handler interface {
        ServeHTTP(ResponseWriter, *Request)
    }
    // The HandlerFunc type is an adapter to allow the use of
    // ordinary functions as HTTP handlers.  If f is a function
    // with the appropriate signature, HandlerFunc(f) is a
    // Handler object that calls f.
    type HandlerFunc func(ResponseWriter, *Request)
    
    // ServeHTTP calls f(w, r).
    func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
        f(w, r)
    // Handle registers the handler for the given pattern
    // in the DefaultServeMux.
    // The documentation for ServeMux explains how patterns are matched.
    func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }
    
    // HandleFunc registers the handler function for the given pattern
    // in the DefaultServeMux.
    // The documentation for ServeMux explains how patterns are matched.
    func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        DefaultServeMux.HandleFunc(pattern, handler)
    }

    Now we know that both of http.HandleFunc and http.Handle invoke function of DefaultServeMux.

    b) DefaultServeMux

    // NewServeMux allocates and returns a new ServeMux.
    func NewServeMux() *ServeMux { return &ServeMux{m: make(map[string]muxEntry)} }
    
    // DefaultServeMux is the default ServeMux used by Serve.
    var DefaultServeMux = NewServeMux()
    // ServeMux is an HTTP request multiplexer.
    // It matches the URL of each incoming request against a list of registered
    // patterns and calls the handler for the pattern that
    // most closely matches the URL.
    //
    type ServeMux struct {
        mu    sync.RWMutex
        m     map[string]muxEntry
        hosts bool // whether any patterns contain hostnames
    }
    
    type muxEntry struct {
        explicit bool
        h        Handler
        pattern  string
    }
    // HandleFunc registers the handler function for the given pattern.
    func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request)) {
        mux.Handle(pattern, HandlerFunc(handler))
    }
    // Handle registers the handler for the given pattern.
    // If a handler already exists for pattern, Handle panics.
    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")
        }
        if mux.m[pattern].explicit {
            panic("http: multiple registrations for " + pattern)
        }
    
        mux.m[pattern] = muxEntry{explicit: true, h: handler, pattern: pattern}
    
        if 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 := pattern
            if 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}
        }
    }

    2. rounter in beego

    1) Get and Post router

    (i) sample code

    beego.Get("/",func(ctx *context.Context){
         ctx.Output.Body([]byte("hello world"))
    })
    beego.Post("/alice",func(ctx *context.Context){
         ctx.Output.Body([]byte("bob"))
    })

    (ii) implementation of Get router

    (a) func Get(rootpath string, f FilterFunc) *App

    // FilterFunc defines filter function type.
    type FilterFunc func(*context.Context)
    
    // register router for Get method
    // usage:
    //    beego.Get("/", func(ctx *context.Context){
    //          ctx.Output.Body("hello world")
    //    })
    func Get(rootpath string, f FilterFunc) *App {
        BeeApp.Handlers.Get(rootpath, f)
        return BeeApp
    }
    
    // create beego application
    BeeApp = NewApp()
    
    // NewApp returns a new beego application.
    func NewApp() *App {
        cr := NewControllerRegister()
        app := &App{Handlers: cr, Server: &http.Server{}}
        return app
    }
    
    
    // App defines beego application with a new PatternServeMux.
    type App struct {
        Handlers *ControllerRegistor
        Server   *http.Server
    }

    (b) ControllerRegistor

    // ControllerRegistor containers registered router rules, controller handlers and filters.
    type ControllerRegistor struct {
        routers      map[string]*Tree
        enableFilter bool
        filters      map[int][]*FilterRouter
    }
    
    // NewControllerRegister returns a new ControllerRegistor.
    func NewControllerRegister() *ControllerRegistor {
        return &ControllerRegistor{
            routers: make(map[string]*Tree),
            filters: make(map[int][]*FilterRouter),
        }
    }
    // add get method
    // usage:
    //    Get("/", func(ctx *context.Context){
    //          ctx.Output.Body("hello world")
    //    })
    func (p *ControllerRegistor) Get(pattern string, f FilterFunc) {
        p.AddMethod("get", pattern, f)
    }
    // add http method router
    // usage:
    //    AddMethod("get","/api/:id", func(ctx *context.Context){
    //          ctx.Output.Body("hello world")
    //    })
    func (p *ControllerRegistor) AddMethod(method, pattern string, f FilterFunc) {
        if _, ok := HTTPMETHOD[strings.ToUpper(method)]; method != "*" && !ok {
            panic("not support http method: " + method)
        }
        route := &controllerInfo{}
        route.pattern = pattern
        route.routerType = routerTypeRESTFul
        route.runfunction = f
        methods := make(map[string]string)
        if method == "*" {
            for _, val := range HTTPMETHOD {
                methods[val] = val
            }
        } else {
            methods[strings.ToUpper(method)] = strings.ToUpper(method)
        }
        route.methods = methods
        for k, _ := range methods {
            if k == "*" {
                for _, m := range HTTPMETHOD {
                    p.addToRouter(m, pattern, route)
                }
            } else {
                p.addToRouter(k, pattern, route)
            }
        }
    }
    func (p *ControllerRegistor) addToRouter(method, pattern string, r *controllerInfo) {
        if t, ok := p.routers[method]; ok {
            t.AddRouter(pattern, r)
        } else {
            t := NewTree()
            t.AddRouter(pattern, r)
            p.routers[method] = t
        }
    }

    appendix:

    // supported http methods.
        HTTPMETHOD = map[string]string{
            "GET":     "GET",
            "POST":    "POST",
            "PUT":     "PUT",
            "DELETE":  "DELETE",
            "PATCH":   "PATCH",
            "OPTIONS": "OPTIONS",
            "HEAD":    "HEAD",
            "TRACE":   "TRACE",
            "CONNECT": "CONNECT",
        }
    type controllerInfo struct {
        pattern        string
        controllerType reflect.Type
        methods        map[string]string
        handler        http.Handler
        runfunction    FilterFunc
        routerType     int
    }

    c) Tree

    type Tree struct {
        //search fix route first
        fixrouters map[string]*Tree
    
        //if set, failure to match fixrouters search then search wildcard
        wildcard *Tree
    
        //if set, failure to match wildcard search
        leaves []*leafInfo
    }
    
    func NewTree() *Tree {
        return &Tree{
            fixrouters: make(map[string]*Tree),
        }
    }
    
    // add Tree to the exist Tree
    // prefix should has no params
    func (t *Tree) AddTree(prefix string, tree *Tree) {
        t.addtree(splitPath(prefix), tree, nil, "")
    }
    func (t *Tree) addtree(segments []string, tree *Tree, wildcards []string, reg string) {
        if len(segments) == 0 {
            panic("prefix should has path")
        }
        seg := segments[0]
        iswild, params, regexpStr := splitSegment(seg)
        if len(segments) == 1 {
            if iswild {
                if regexpStr != "" {
                    if reg == "" {
                        rr := ""
                        for _, w := range wildcards {
                            if w == "." || w == ":" {
                                continue
                            }
                            if w == ":splat" {
                                rr = rr + "(.+)/"
                            } else {
                                rr = rr + "([^/]+)/"
                            }
                        }
                        regexpStr = rr + regexpStr
                    } else {
                        regexpStr = "/" + regexpStr
                    }
                } else {
                    for _, w := range wildcards {
                        if w == "." || w == ":" {
                            continue
                        }
                        regexpStr = "([^/]+)/" + regexpStr
                    }
                }
                reg = strings.Trim(reg+regexpStr, "/")
                filterTreeWithPrefix(tree, append(wildcards, params...), reg)
                t.wildcard = tree
            } else {
                filterTreeWithPrefix(tree, append(wildcards, params...), reg)
                t.fixrouters[seg] = tree
            }
            return
        }
        if iswild {
            if t.wildcard == nil {
                t.wildcard = NewTree()
            }
            if regexpStr != "" {
                if reg == "" {
                    rr := ""
                    for _, w := range wildcards {
                        if w == "." || w == ":" {
                            continue
                        }
                        if w == ":splat" {
                            rr = rr + "(.+)/"
                        } else {
                            rr = rr + "([^/]+)/"
                        }
                    }
                    regexpStr = rr + regexpStr + "/"
                } else {
                    regexpStr = "/" + regexpStr + "/"
                }
            } else {
                for _, w := range wildcards {
                    if w == "." || w == ":" {
                        continue
                    }
                    if w == ":splat" {
                        regexpStr = "(.+)/" + regexpStr
                    } else {
                        regexpStr = "([^/]+)/" + regexpStr
                    }
                }
            }
            reg = reg + regexpStr
            t.wildcard.addtree(segments[1:], tree, append(wildcards, params...), reg)
        } else {
            subTree := NewTree()
            t.fixrouters[seg] = subTree
            subTree.addtree(segments[1:], tree, append(wildcards, params...), reg)
        }
    }

    I don't know what the Tree presents now.

    I will figure it out later.

  • 相关阅读:
    微信报错 config:fail.Error:invalid signature
    js动态添加onload、onresize、onscroll事件(另类方法)
    Jquery 读取表单选中值
    Jquery事件
    Jquery
    PHP-query 的用法
    php-数据库访问--数据修改
    php-数据库访问--增、删、改
    php-访问数据库
    php-设计模式
  • 原文地址:https://www.cnblogs.com/harrysun/p/4079940.html
Copyright © 2020-2023  润新知