写点什么

Golang 框架探索 (一)

用户头像
余歌
关注
发布于: 2020 年 09 月 21 日

ps. 搬运自我的个人知乎文章


最近闲来无事,捣鼓了一下 Golang 的 Web 框架。这一篇文章主要是梳理一下 Web 框架的执行逻辑,真正开始上手撸代码和踩坑要到下一篇。

因为是 Java 选手,刚开始学 Go 不久,代码风格可能比较 Java。

另外有一些题外话,我最初开始学习 Web 框架是一本 Java 的讲解 Web 框架的书籍,名字叫《框架探险》。

但是 Java 的 Web 框架和 Go 的 Web 框架还是有不少的区别,学习 Go 的话不是很建议使用这本书。


Web 框架基本设计


现代的 Web 后端框架中,所有框架的设计都会提供一部分共同的功能。这部分功能是 Web 框架的最基础功能:建立 url 对函数的映射,对 Request / Response 进行解析和封装。这些框架减轻了工作时的重复劳动与复杂繁琐的 api 调用,提升了应用的开发速度和可维护性。


框架不管是使用过滤器这样的设计(比如 struts),还是直接使用一个函数处理所有的请求(比如 spring、gin 等等),都是使用了单一入口,即所有请求通过原生的 api 进入到一个统一的处理模块。


请求进来时,在这个单一模块中查找请求的路由(uri)和方法(method)所对应的处理这个路由的函数。若查找不到,则返回 404(NOT FOUND)或 405(MOTHOD NOW ALLOW)。


找到对应的处理函数后取出这个函数,根据解析请求中的参数,如 get 请求中 url 的参数、post 请求中 body 里的参数,解析并封装后执行该函数,得到返回对象再进行解析通过设定好的格式(json/xml/html 等)序列化,最后原生的方法返回。


下面是原生 api 和使用框架的对比:



我们希望使用框架能够写出如下的代码:


package main
import "begonia"
func main(){ app := application.Init()
app.Get("/hello", func(ctx *begonia.Context) { ctx.String("hello world") })
app.Post("/welcome", func(ctx *begonia.Context) { name := ctx.Param("name") ctx.String("hello " + name) })
app.Start(1234)}
复制代码


对于一个框架来说,最基础的模块就是路由模块了,即 uri 对执行函数的映射。下面一个部分我们来聊聊这个路由。


路由模块


在阅读了多个语言多个框架的路由解析部分源码后,一般路由的实现大体分为两个思路:哈希表和 Trie 树(前缀树)。


使用哈希表的为:


  • Java Spring


而我所看过的 golang 的框架,全部使用了 Trie 树来实现路由的解析分发


  • beego

  • gin

  • echo


我们这篇文章里简单来说一下两种实现的思路。


路由的哈希表实现


由于各大语言都拥有了原生的哈希表实现,这里我们就不赘述如何实现一个哈希表了,感兴趣可以自行 百度/谷歌 一下。


我们可以针对每个方法创建一个哈希表,每添加一个路由,在对应方法的哈希表下建立一个键值对即可。


当请求进来时,根据 uri 查找路由,若查找得到则封装请求参数并执行。若查找不到,则去其他方法的哈希表里再查询一下,这一步查到的到返回405 method not allow,查找不到返回404 not found



路由的 Trie 树实现


这里我聊一聊使用压缩Trie树来添加和查找路由,代码实现我们下一篇文章来专门分析。


Trie树又称前缀树字典树,思路是将字符串按每个字符存储在树的节点上,具有公共前缀的单词共享一个或几个父节点。例如:"wechat"、"weibo"、"ware"、"hi"、"te"存储在Trie树上的情况如图所示



但是对于 url 来说,会有很多的 uri 具有公共前缀,但是具有较长的非公共的后缀,这个时候我们就需要使用到压缩Trie树了。


压缩Trie树其实是上面的普通 Trie 树的升级版,比普通Trie树占用更少的内存空间。大题思路是在普通Trie树上将长链压缩为一个节点。上图所示的数据结构压缩后如下图所示:



对比上面的普通 Trie 树,不难发现每个节点不存在单独的子节点,没有单独的长链存在了。


写在最后


在 Web 框架中除了路由,还拥有其他非常重要的模块。这一篇文章只是一个简单的 Web 框架针对路由的一些分析。在下一篇我会详细分析并使用代码实现压缩 Trie 树路由


发布于: 2020 年 09 月 21 日阅读数: 163
用户头像

余歌

关注

还未添加个人签名 2020.08.10 加入

还未添加个人简介

评论

发布
暂无评论
Golang框架探索(一)