假如让你来设计group api, 你该怎么设计呢?
group api 和普通api的区别在于前缀不同,如果group api的版本为v1.0 那么相对应的url为/v1.0/xxx, 如果是普通api的话那么api相对应的版本为/xxx
在gin web framework 中设计的原则也是以相对路径来区分。
// RouterGroup is used internally to configure router, a RouterGroup is associated with // a prefix and an array of handlers (middleware). type RouterGroup struct { Handlers HandlersChain #处理函数 basePath string #相对路径 engine *Engine #存在哪个engine上 root bool #基于基树判断是否为root }
先看gin中group 的添加规则:
router := gin.New() users := router.Group("/users")
先看gin.New()默认的basePath是什么。
// New returns a new blank Engine instance without any middleware attached. // By default the configuration is: // - RedirectTrailingSlash: true // - RedirectFixedPath: false // - HandleMethodNotAllowed: false // - ForwardedByClientIP: true // - UseRawPath: false // - UnescapePathValues: true func New() *Engine { debugPrintWARNINGNew() engine := &Engine{ RouterGroup: RouterGroup{ Handlers: nil, basePath: "/", #默认为“/” root: true, }, FuncMap: template.FuncMap{}, RedirectTrailingSlash: true, RedirectFixedPath: false, HandleMethodNotAllowed: false, ForwardedByClientIP: true, AppEngine: defaultAppEngine, UseRawPath: false, UnescapePathValues: true, MaxMultipartMemory: defaultMultipartMemory, trees: make(methodTrees, 0, 9), delims: render.Delims{Left: "{{", Right: "}}"}, secureJsonPrefix: "while(1);", } engine.RouterGroup.engine = engine engine.pool.New = func() interface{} { return engine.allocateContext() } return engine }
查看router.Group("/users") 的调用
// Group creates a new router group. You should add all the routes that have common middlewares or the same path prefix. // For example, all the routes that use a common middleware for authorization could be grouped. func (group *RouterGroup) Group(relativePath string, handlers ...HandlerFunc) *RouterGroup { return &RouterGroup{ Handlers: group.combineHandlers(handlers), basePath: group.calculateAbsolutePath(relativePath), #根据relativePath这个参数,计算basePath engine: group.engine, } }
查看group.calculateAbsolutePath(relativePath) 的调用
func (group *RouterGroup) calculateAbsolutePath(relativePath string) string { return joinPaths(group.basePath, relativePath) }
再查看joinPaths的实现
func joinPaths(absolutePath, relativePath string) string { if relativePath == "" { #如果没有relativePath 直接返回absolutePath,默认为“/” return absolutePath } #处理最后的“/” finalPath := path.Join(absolutePath, relativePath) appendSlash := lastChar(relativePath) == '/' && lastChar(finalPath) != '/' if appendSlash { return finalPath + "/" } return finalPath }