超轻量级 Go 框架 Aurora Web

Aurora Web 使用示例

其实在使用的方式上和大部分 go web 框架相差不大
简单的写一个入门demo:

package main

import (
  "github.com/aurora-go/aurora/aurora"
)

func main() {
  //获取 aurora 路由实例
  a := aurora.New()
  // GET 方法注册 web get请求
  a.GET("/", func(request aurora.Request) interface{} {
    return nil
  })
  // 启动服务器 默认端口8080,更改端口号 a.Guide(”8081“) 即可
  a.Guide("")
}
复制代码

废话就不多说了,下面对Aurora Web做一个简单的介绍

路由设计

起初在没有参考优秀的web框架时,也曾多次尝试对路由存储的设计,但并没有想到更好的方式来灵活处理,通过gin和httprouter的源码借鉴,也作出了选择。采用前缀树的方式来对路由进行切割存储(切割存储存在一些弊端,同时也成为了 aurora 的短板之处)
先贴出router 核心代码以便分析:

// ServerRouter Aurora核心路由器
type route struct {
  mx          *sync.Mutex
  tree        map[string]*node // 路由树根节点
  defaultView Views            // 默认视图处理器,初始化采用 Aurora 实现的函数进行渲染
  ar          *Aurora          // Aurora 引用
}

// Node 路由节点
type node struct {
  Path   string   //当前节点路径
  handle []Handel //服务处理函数
  Child  []*node  //子节点
}
复制代码

下面的规则是在开发过程中累计起来的,有需要的伙伴可以参考一下
路由器规则:

  1. 无法存储相同的路径,形同路径的判定:校验参数相同,并且节点函数不为nil,节点函数为nil的节点说明,这个路径是未注册过,被提取为公共根。注册相同路径处理函数,默认覆盖前面相同的处理函数。
  2. 路径查找按照逐层检索
  3. 路由树上面存储者当前路径匹配的服务处理函数
  4. 注册路径必须以 / 开头
  5. 发生公共根。节点和被添加路径产生公共根,提取公共根后,若公共根未注册,服务处理函数将为ni,若节点恰好是公共根,则设置函数
  6. REST 风格注册。同一个根路径下只能有一个REST 子路径,REST 作为根路径也只能拥有一个REST 子路径,REST 路径会和其它非REST同级路径发生冲突。
  7. 注册路径不能以/结尾(bug未修复,/user /user/ 产生 /user 的公共根 使用切割解析路径方式,解析子路径,拼接剩余子路径会存在bug ,注册路径的时候强制无法注册 / 结尾的 url)
  8. 浏览器访问接口,不能带有可编码符号,特别是{} ,{}是框架解析rest ful 参数的标识,接收到带有{},比如/a/b/{sss}/c,带有{或}的请求都视为非法url

现在我有以下的Web接口开始注册:

package main

import (
  "github.com/aurora-go/aurora/aurora"
)

func Default(r aurora.Request) interface{} {

  return "nil"
}
func main() {
  //获取 aurora 路由实例
  a := aurora.New()
  a.GET("/aaa/bbb", Default)
  a.GET("/aa", Default)
  a.GET("/", Default)
  a.GET("/bbb", Default)
  a.GET("/a/c", Default)
  a.GET("/ccc", Default)
  a.GET("/ccc/ddd", Default)
  a.GET("/ccc/ddd/{a}/{b}", Default)
  a.GET("/eee/aaa", Default)
  a.GET("/eee/aaa/oo", Default)
  a.GET("/eee/aaa/oo/{ccc}", Default)
  a.GET("/eee/aaa/oo/{ccc}/abc", Default)
  // 启动服务器 默认端口8080,更改端口号 a.Guide(”8081“) 即可
  a.Guide("")
}
复制代码

上面的接口大致会呈现一下的数据结构
l路由器构建结构图
接口比较多,选了开始的一小部分表示出来
在前缀树中我们能找到几条完整路径:

  • /
  • /aa
  • /a
  • /a/c
  • /aaa/bbb
  • /ccc/ddd/{a}/{b}
  • /eee/aaa

在前缀书上,我们可以走出以上的路径,每走一步进行一个拼接能得到一个完整的路径,在一个请求达到之后,开始在路由树上面一步一步的走,没有找到则算改请求是无效的。

现在我们知道了路由原理,从图中和前缀树的构造规则来看,子路径越多,被切割的层数也就越深。而且在构造路由书的中间存在对公共部分的提取,有些节点不一定是一个接口。

生命周期

初始化阶段

aurora初始化图
初始化图从上向下看

请求处理

一个请求的处理执行图,参考
一个浏览器的请求周期如下图所示,经过路由判断类型,静态资源(html, 图片,js等)无须查找接口直接响应,根据接口的不同和预处理配置的不同执行到处理函数,然后做出响应。

静态资源

关于静态资源的实现细节可以查阅源码,在此处简单解说一下。更具go web的原生处理方式,想要发送资源只能通过写入数据,静态资源的查找是核心关键,读取服务器上指定路径的资源,添加上对应的头类型即可完成资源的访问,浏览器就能够正确的解读资源并展现出来。aurora 的静态资源处理做了最简单的封装,其默认情况下项目根目录就是存放处,当然也提供了指定资源位置的操作。

预处理机制

预处理机制,就是对Web 业务逻辑的执行之前进行抢先执行,Go 用户常称作中间件,Java 用户常叫做拦截器或者过滤器。我是从Java web 转到 Go Web ,各自的叫法也都习惯了,起初对预处理的设计模仿了Java 的拦截器处理方式,但是用在Go上面能实现效果,但是性能确是不怎么样,也可能是经验不足没有设计好。还是得站在巨人的肩膀上做设计更加便捷,我采取和gin类似的做法,根据具全局和局部,按顺序执行下去即可。

参数解析

aurora 的参数解析,选择了map[string]interfac{} 类型 ,把所有类型的请求参数全部解析到 map 中更具实际情况直接取值使用即可,同时map中初始化内置了 go web 的原生请求体和响应体,提供开发者使用。

响应处理

个人对于gin的处理方式,其实有一点不太习惯的,gin的处理函数没有返回值,这个机制让我在某个逻辑条件下处理完响应或者处理完错误时候 没有下意识的 return 结束执行,导致经常报错。借着这个机会我给aurora的处理函数添加了返回值 interface{} 用于处理多种类型的数据,此时设计了返回值处理,也对我的预处理执行链提供了意想不到的 便利。

代码仓库

最后附上框架github 库 Aurora Web,相关使用文档。该框架是在学习go开发期间零碎时间一点一点起来的,至今也有大半年时间了,我还会继续维护下去,有意思的小伙伴可以尝试一下使用体验感,能有助于我修改和维护没有发现的bug?

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享