天天看点

go web框架_Golang框架探索(一)

go web框架_Golang框架探索(一)

这篇文章是搬运自我的个人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和使用框架的对比:

go web框架_Golang框架探索(一)

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

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

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

路由的哈希表实现

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

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

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

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

405 method not allow

,查找不到返回

404 not found

go web框架_Golang框架探索(一)

路由的Trie树实现

这里我聊一聊使用

压缩Trie树

来添加和查找路由,代码实现我们下一篇文章来专门分析。

Trie树

又称

前缀树

字典树

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

Trie树

上的情况如图所示

go web框架_Golang框架探索(一)

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

压缩Trie树

了。

压缩Trie树

其实是上面的普通Trie树的升级版,比

普通Trie树

占用更少的内存空间。大题思路是在

普通Trie树

上将长链压缩为一个节点。上图所示的数据结构压缩后如下图所示:

go web框架_Golang框架探索(一)

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

写在最后

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

继续阅读