.
.
.
├── main.go // 程序的入口
├── database // 数据库配置相关的代码
├── common
│ └── options.go // 全局通用的配置
├── middlewares
│ ├── auth.go // 鉴权中间件
│ ├── ip.go // ip拦截中间件
│ ├── unit_test.go // 单元测试
│ ├── white.txt // ip白名单
│ └── black.txt // ip黑名单
│
├── users
│ ├── models.go // 数据模型及数据库相关操作
│ ├── routers.go // 路由管理
│ ├── serializers.go // response的格式序列化
│ ├── service.go // 业务逻辑代码 │
│ ├── unit_test.go // 黑盒单元测试
│ └── validators.go // 对前端传来的数据进行验证
├── walls
├── ...
├── utils // 里面定义了一些实用的工具函数
...
http请求 -> 中间件检验 -> 进入路由管理 -> 数据验证 -> 业务逻辑(CRUD) -> 序列化 -> 返回
使用gorm框架连接数据库和对数据库进行操作。
使用gin框架实现路由管理。
整个程序主要功能由CRUD完成,较为简单, 不做说明。
下对几个创新功能进行说明:
使用jwt根据用户id和过期时间生成token, 前端只需要使用token即可进行一些受限访问。
具体流程为:收到http请求, 鉴权中间件对http header里的字段进行校验,并解析出id写入请求上下文, 然后在真正的处理逻辑中就好像请求是带着用户id来的。
使用Redis内存数据库实现ip拦截功能
具体实现为: 在Redis中记录<ip, 访问次数的键值对>, 每隔固定的时间将访问次数清零。
若访问次数超过一定的范围,则会直接将请求拦截。
经测试,拦截一个请求只需要 50us 左右, 阻止了一定的恶意请求。
固定时间及次数阈值可以在options.go中修改。
默认为同一ip在1s内至多50次请求。
同时还支持自定义ip黑白名单功能,在black.txt和white.txt中自行添加ip。
注意: 每个ip写一行,且前后不能有多余的空格。
在ip黑白名单中的ip不会经过ip拦截逻辑。
由于我们实现的是一个典型的读请求多写请求少的应用, 我们引入cache机制。
对所有GET请求缓存,对于短时间内的相同请求,我们会直接从cache中读取并返回。
经过测试,cache命中的情况下,响应时间大概只有700us, 而正常请求需要 2~3ms的响应时间。
cache实质上是一个线程安全的哈希表, 我们使用请求的url(有时要加上用户id)作为键, 请求的response作为值
对于所有的GET请求,我们在路由返回之前先将其加入cache, 每次GET请求进来时,先在cache中查询, 若命中,则直接返回。
对于会修改数据库的操作,我们将cache中受影响的键删除,以保证数据的正确性。
cache过期时间和垃圾清理时间可以在options.go中修改。
默认cache两分钟过期。