相信你对路由是干啥的已经有大致了解,具体来说就是让 Web 服务器根据规则,理解 HTTP 请求中的信息,匹配查找出对应的控制器,再将请求传递给控制器执行业务逻辑,简单来说就是制定匹配规则。
路由规则的需求回到我们的框架,开头我们说过希望使用者高效、易用地使用路由模块,那出于这一点考虑,基本需求可以有哪些呢?按照从简单到复杂排序,路由需求我整理成下面四点:
需求 1:HTTP 方法匹配早期的 WebService 比较简单,HTTP 请求体中的 Request Line 或许只会使用到 Request-URI 部分,但是随着 REST 风格 WebService 的流行,为了让 URI 更具可读性,在现在的路由输入中,HTTP Method 也是很重要的一部分了,所以,我们框架也需要支持多种 HTTP Method,比如 GET、POST、PUT、DELETE。
需求 2:静态路由匹配静态路由匹配是一个路由的基本功能,指的是路由规则中没有可变参数,即路由规则地址是固定的,与 Request-URI 完全匹配。我们在第一讲中提到的 DefaultServerMux 这个路由器,从内部的 map 中直接根据 key 寻找 value ,这种查找路由的方式就是静态路由匹配。
需求 3:批量通用前缀因为业务模块的划分,我们会同时为某个业务模块注册一批路由,所以在路由注册过程中,为了路由的可读性,一般习惯统一定义这批路由的通用前缀。比如 /user/info、/user/login 都是以 /user 开头,很方便使用者了解页面所属模块。所以如果路由有能力统一定义批量的通用前缀,那么在注册路由的过程中,会带来很大的便利。
需求 4:动态路由匹配这个需求是针对需求 2 改进的,因为 URL 中某个字段或者某些字段并不是固定的,是按照一定规则(比如是数字)变化的。那么,我们希望路由也能够支持这个规则,将这个动态变化的路由 URL 匹配出来。所以我们需要,使用自己定义的路由来补充,只支持静态匹配的 DefaultServerMux 默认路由。
// 注册路由规则func registerRouter(core *framework.Core) {// 需求1+2:HTTP方法+静态路由匹配core.Post("/user/login", UserLoginController)// 需求3:批量通用前缀subjectApi := core.Group("/subject"){subjectApi.Post("/add", SubjectAddController)// 需求4:动态路由subjectApi.Delete("/:id", SubjectDelController)subjectApi.Put("/:id", SubjectUpdateController)subjectApi.Get("/:id", SubjectGetController)subjectApi.Get("/list/all", SubjectListController)}}
按框架使用者使用路由的顺序分成四步来完善这个结构:定义路由 map、注册路由、匹配路由、填充 ServeHTTP 方法。
// 框架核心结构type Core struct {}// 初始化框架核心结构func NewCore() *Core {return &Core{}}// 框架核心结构实现Handler接口func (c *Core) ServeHTTP(response http.ResponseWriter, request *http.Request) {// TODO}
// 框架核心结构type Core struct {router map[string]map[string]ControllerHandler // 二级map}// 初始化框架核心结构func NewCore() *Core {// 定义二级mapgetRouter := map[string]ControllerHandler{}postRouter := map[string]ControllerHandler{}putRouter := map[string]ControllerHandler{}deleteRouter := map[string]ControllerHandler{}// 将二级map写入一级maprouter := map[string]map[string]ControllerHandler{}router["GET"] = getRouterrouter["POST"] = postRouterrouter["PUT"] = putRouterrouter["DELETE"] = deleteRouterreturn &Core{router: router}}
// 对应 Method = Getfunc (c *Core) Get(url string, handler ControllerHandler) {upperUrl := strings.ToUpper(url)c.router["GET"][upperUrl] = handler}// 对应 Method = POSTfunc (c *Core) Post(url string, handler ControllerHandler) {upperUrl := strings.ToUpper(url)c.router["POST"][upperUrl] = handler}// 对应 Method = PUTfunc (c *Core) Put(url string, handler ControllerHandler) {upperUrl := strings.ToUpper(url)c.router["PUT"][upperUrl] = handler}// 对应 Method = DELETEfunc (c *Core) Delete(url string, handler ControllerHandler) {upperUrl := strings.ToUpper(url)c.router["DELETE"][upperUrl] = handler}
实现批量通用前缀
// 注册路由规则func registerRouter(core *framework.Core) {// 需求1+2:HTTP方法+静态路由匹配core.Get("/user/login", UserLoginController)// 需求3:批量通用前缀subjectApi := core.Group("/subject"){subjectApi.Get("/list", SubjectListController)}}
