这篇文章是搬运自我的个人blog:
MashiroC的奇思妙想

最近闲来无事,捣鼓了一下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

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

路由的哈希表实现

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

Go的map、Java的HashMap、pthon的dict采用的是哈希表实现,而c++的map使用的是红黑树,哈希表是unordered_map,这里提醒一下。

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

405 method not allow404 not found

路由的Trie树实现

压缩Trie树
Trie树前缀树字典树Trie树



压缩Trie树
压缩Trie树普通Trie树普通Trie树



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

写在最后

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