mygin-仿照Gin开发的一个Web应用框架

前言

仿照 Gin 开发一个基本功能完善的 Web 应用框架,包括请求处理、上下文、路由系统(包含分组控制及动态路由,基于正则还是基于前缀树实现自己决定)、中间件加载、模板文件等模块

因为突然被朋友叫出去玩,导致开发的时间不是很连贯,写的途中也没有好好记录,所以干脆在开发完成后来写一篇回顾或者说是总结。

我一开始的想法是尽量少看Gin的代码(看太多就变成抄写了),通过自己的思路来实现一个web框架,也就是基本功能都通过对于net/http的封装来实现,因此也能看到我的代码中有些地方写得可能比较任性(刚开始写go,对一些标准库不太熟悉,有些可以用标准库的地方可能就按自己的想法来实现了),这也导致了我拓展的困难,经常写一个新功能要把之前的部分重构一遍。但终归要仿照Gin来写,所以代码中大部分函数签名都和Gin中的相同,也方便编写测试代码。

代码实现了请求处理、上下文、路由系统(基于前缀树)、中间件加载、模版文件、静态文件等模块,项目地址:l1nk4i/mygin (github.com)

1
2
3
4
5
6
mygin/
├── context.go
├── mygin.go
├── routergroup.go
├── tree.go
└── utils.go

代码编写思路

请求处理

net/http中可以通过实现http.ServeHTTP接口来实现对于每个请求的处理,这就需要定义一个结构体Engine来实现这个接口。

Engine也就是作为处理每个http请求,启动web服务器的对象。

上下文

在编写中间件或者处理函数时,通常都需要很多参数,比如ResponseWriter, Request,方便起见就是将这些参数进行封装,我们将这些东西都封装进上下文Context中,这样在编写中间件时只需要输入上下文Context即可拿到需要的所有参数。

Context的生命周期就和一个请求相同,每一个Context都是和一个请求绑定的,封装了请求的信息和对应响应的信息。这样对于每一个请求我们只需要操作其对应的Context就行了,同时也方便了函数间的数据传输。

路由系统

通过前缀树来实现,把每个路由的handlers都直接挂到相对应的路由node上,通过注册顺序来决定执行的顺序。因为每个方法注册的处理函数不同,所以每个方法都会有一棵独立的树。

静态路由

只需要通过Engine来注册路由以及对应的handler,在处理路由时直接搜索对应路由。

动态路由

需要增加节点类型,并且在处理路由时把对应参数的值存入Context

分组路由与中间件

我认为路由分组通常是和中间件绑定的,比如对于一组路由都需要鉴权。

这里定义一个新的结构体RouterGroup存放分组的路径和handlers,实现所有注册路径的方法,同时嵌入Engine,即把Engine看做是根节点的RouterGroup

那么中间件的实现就是把RouterGroup和中间件函数对应起来,在注册路由的时候加入处理函数的列表。

模板文件

模版的实现主要就是对于html/template的简单封装

收获

这次是速通了一下go就开始写这个项目,编写过程中最直观的收获就是理解了一个web框架都实现了哪些功能,怎么去实现这些功能,也大致熟悉了go的语法。

Web框架也就是对于一些标准库功能的扩展和封装,通过对于底层细节的封装来方便我们重用一些功能,提升开发的效率,简化编写的代码。

那么我怎样才能完全独立编写一个类似于Gin这样的框架呢,首先需要我对底层的一些库的使用都很熟悉,其次需要我已经理解一些别的框架的思想来确定要实现的功能,最重要的还是明确编写需求。