本书未发布

5.6. Eudore路由器

未匹配的标注

Router

eudore.Router主要实现路由注册、中间件注册、处理函数扩展三项功能。

Router接口定义:

// Router interface needs to implement the router method and the router core two interfaces.
//
// RouterCore implements route matching details. RouterMethod calls RouterCore to provide methods for external use.
//
// Do not use the RouterCore method to register routes directly at any time. You should use the Add ... method of RouterMethod.
//
// Router 接口,需要实现路由器方法、路由器核心两个接口。
//
// RouterCore实现路由匹配细节,RouterMethod调用RouterCore提供对外使用的方法。
//
// 任何时候请不要使用RouterCore的方法直接注册路由,应该使用RouterMethod的Add...方法。
type Router interface {
    RouterCore
    RouterMethod
}

// The RouterCore interface performs registration of the route and matches a request and returns the handler.
//
// RouterCore mainly implements routing matching related details.
//
// RouterCore接口,执行路由的注册和匹配一个请求并返回处理者。
//
// RouterCore主要实现路由匹配相关细节。
type RouterCore interface {
    HandleFunc(string, string, HandlerFuncs)
    Match(string, string, *Params) HandlerFuncs
}

// RouterMethod The default directly registered interface of the route. Set the routing parameters, group routing, middleware, function extensions, controllers and other behaviors.
//
// RouterMethod 路由默认直接注册的接口,设置路由参数、组路由、中间件、函数扩展、控制器等行为。
type RouterMethod interface {
    Group(string) Router
    Params() *Params
    AddHandler(string, string, ...interface{}) error
    AddController(...Controller) error
    AddMiddleware(...interface{}) error
    AddHandlerExtend(...interface{}) error
    AnyFunc(string, ...interface{})
    GetFunc(string, ...interface{})
    PostFunc(string, ...interface{})
    PutFunc(string, ...interface{})
    DeleteFunc(string, ...interface{})
    HeadFunc(string, ...interface{})
    PatchFunc(string, ...interface{})
    OptionsFunc(string, ...interface{})
}

Router

路由器接口由路由器核心接口和路由器方法接口组合而成,路由器核心接口主要复制路由的注册和匹配;路由器方法接口实现组路由、路由参数设置、控制器添加、中间件添加、处理函数扩展添加和注册路由。

RouterCore

路由器核心实现路由的注册和匹配。

HandleFunc就是注册一个方法路径下的多个请求处理者。

Match就是对应的匹配实现,根据方法路径匹配出对应的多个请求处理者,同时添加对应的Params。

RouterMethod

RouterMethod接口主要有下面方法

type RouterMethod {
    Group(string) Router
    Params() *Params
    AddHandler(string, string, ...interface{}) error
    AddController(...Controller) error
    AddMiddleware(...interface{}) error
    AddHandlerExtend(...interface{}) error
    AnyFunc(string, ...interface{})
    GetFunc(string, ...interface{})
    ...
}

Group

Group 方法返回一个新的组路由器。

每个Group组路由注册的参数、中间件、函数扩展都不会影响上级,但是下级会继承上级数据。

新的Router将使用旧的RouterCore和Print对象;中间件信息和路由参数从上级深拷贝一份,同时处理Group参数。

以及链式创建一个新的HandlerExtender,若HandlerExtender无法注册的类型将调用上一个Router.HandlerExtender处理。

最顶级HandlerExtender对象为defaultHandlerExtend,可以使用RegisterHandlerExtend函数和NewHandlerFuncs函数调用defaultHandlerExtend对象。

func (m *RouterStd) Group(path string) Router {
    // 构建新的路由方法配置器
    return &RouterStd{
        RouterCore:      m.RouterCore,
        HandlerExtender: NewHandlerExtendWarp(m.HandlerExtender),
        params:          m.ParamsCombine(path),
        Print:           m.Print,
    }
}

Get/SetParam

读写参数用于修改当前路由参数,在Group时path中包含的路由默认参数就会解析到新组路由中,同时在注册路由的path也可能会包含路由默认参数,最后这些参数一起注册到路由,在路由匹配命中后会设置到请求上下文中。

在GetParam方法如果键为:eudore.ParamAllKeys和eudore.ParamAllVals可以获取全部路由器参数的键值,建议使用常量不使用字符串,防止在未来为了解决命名冲突而改名常量值,同时这两个key在Context当前并不支持。

AddHandler

AddHandler 添加一个新路由, 允许添加多个请求方法使用','分开。

handler参数使用当前RouterStd的HandlerExtender.NewHandlerFuncs()方法处理,生成对应的HandlerFuncs。

当前Router无法处理,则调用group前的HandlerExtender或defaultHandlerExtend处理,全部无法处理则输出error日志。

会根据当前路由路径匹配到对齐的请求中间件并附加到请求中。

而GetFunc等添加路由的方法和AddHandler行为一样,只不过AddHandler可以传入指定方法作为路由方法。

AddController

调用控制器Inject方法传入控制器和当前路由器注册路由

func (m *RouterStd) AddController(cs ...Controller) error {
    var errs Errors
    for _, c := range cs {
        err := c.Inject(c, m)
        if err != nil {
            err = fmt.Errorf(ErrFormatRouterStdRegisterAddController, err)
            errs.HandleError(err)
            m.PrintError(0, err)
        }
    }
    return errs.GetError()
}

AddMiddleware

AddMiddleware 给路由器添加多个中间件函数,会使用HandlerExtender转换参数。

如果参数数量大于1且第一个参数为字符串类型,会将第一个字符串类型参数作为添加中间件的路径。

func (m *RouterStd) AddMiddleware(hs ...interface{}) error {
    if len(hs) == 0 {
        return nil
    }

    path := m.GetParam("route")
    if len(hs) > 1 {
        perfix, ok := hs[0].(string)
        if ok {
            path = perfix + path
            hs = hs[1:]
        }
    }

    handlers, err := m.newHandlerFuncs(path, hs)
    if err != nil {
        m.PrintError(0, err)
        return err
    }

    m.Middlewares.Insert(path, handlers)
    m.Print("RegisterMiddleware:", path, handlers)
    return nil
}

AddHandlerExtend

AddHandlerExtend 方法给当前Router添加扩展函数。

如果参数数量大于1且第一个参数为字符串类型,会将第一个字符串类型参数作为添加扩展函数的路径。

func (m *RouterStd) AddHandlerExtend(hs ...interface{}) error {
    if len(hs) == 0 {
        return nil
    }

    path := m.GetParam("route")
    if len(hs) > 1 {
        perfix, ok := hs[0].(string)
        if ok {
            path = perfix + path
            hs = hs[1:]
        }
    }

    var errs Errors
    for _, h := range hs {
        err := m.HandlerExtender.RegisterHandlerExtend(path, h)
        if err != nil {
            err = fmt.Errorf(ErrFormatRouterStdRegisterAddHandlerExtend, path, err)
            errs.HandleError(err)
            m.PrintError(0, err)
        }
    }
    return errs.GetError()
}

Middleware

Handler接口定义了处理Context的方法。

type (
    // Context handle func
    HandlerFunc func(Context)
    HandlerFuncs    []HandlerFunc
)

而eudore中间件处理函数与eudore.HanderFunc相同,通过ctx的next实现中间件机制。

func (ctx *ContextBase) SetHandler(fs HandlerFuncs) {
    ctx.index = -1
    ctx.handler = fs
}

func (ctx *ContextBase) Next() {
    ctx.index++
    for ctx.index < len(ctx.handler) {
        ctx.handler[ctx.index](ctx)
        ctx.index++
    }
}

func (ctx *ContextBase) End() {
    ctx.index = 0xff
}

eudore的Middleware是一个函数,类型是eudore.HandlerFunc,可以在中间件类型使用ctx.Next来调用先后续处理函数,然后再继续执行定义的内容,ctx.End直接忽略后续处理。

ctx.Fatal默认会调用ctx.End,也是和ctx.

在ContextBase实现中,将全部请求处理者使用SetHandler方法传递给ctx,然后调用Next方法开始循环执行处理,End方法将执行索引移到到结束,就结束了全部的处理。

Next方法中调用处理,如果处理中调用了Next方法,那么在处理中就会先将后续处理完,才会继续处理,就巧妙实现Pre和Post的Handler的调用,如果处理中没有调用Next方法,就for循环继续执行处理。

例如:

func main() {
    app := eudore.NewCore()
    app.AddMiddleware(func(ctx eudore.Context) {
        ctx.Println("前执行")
        ctx.Next()
        fmt.Println("后执行")
    })
}

反馈和交流请加群组:QQ群373278915

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~