Golang 框架探索 (一)
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 和使用框架的对比:
我们希望使用框架能够写出如下的代码:
对于一个框架来说,最基础的模块就是路由模块了,即 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 树路由
版权声明: 本文为 InfoQ 作者【余歌】的原创文章。
原文链接:【http://xie.infoq.cn/article/d8651fd410455ff59038bcf75】。文章转载请联系作者。
评论