基于Gin框架的网关设计开发
年尾这几天自己研究并开发了一个基于Go语言的网关项目设计开发,并对其进行了开源,需要的小伙伴请点击:【Github地址】自主下载使用,README 中有还算详细的说明文档,本人不喜欢前端,所以也没有去找一个开源的后台页面接入,但提供了相应的数据添加接口,接口地址在项目【DOC】中说明,表结构设计也在【TABLE】中有非常详细的说明。
另外本人还有另一个工具觉得很方便大家:【请求重新提交】
使用注意:
- 项目依赖都是必须的,其配置存放于【conf】配置中心
- 需要根据 TABLE 严格按照说明对MongoDB的数据结构和数据进行控制,否则不能正常使用
- 看完觉得不错,必须✨✨✨✨哦
项目依赖:
- Gin 框架
- Redis
- MongoDB
主要实现功能:
- 路由转发,包括超时设置(基础功能 GET / POST)
- 多 IP / 域名 配置
- 路由 dns (只支持轮训)
- 请求限流
- 数据缓存
- 请求容错
- 统一鉴权
设计目标:
- 模块化
- 配置化
入口:main 函数,为了方便后续的扩展,所以什么也不放
package main import ( "gw/route" ) // main 函数没什么好说的,尽量干净,方便后续的模块添加 func main() { r := route.Route() r.Run(":1323") }
路由:路由采取了分隔,将前后端的路由分开
package route import ( "gw/route/admin" "gw/route/api" "github.com/gin-gonic/gin" ) // 调用设置路由 func Route() *gin.Engine { r := gin.Default() //外部调用路由 api.Route(r) //后台接口调用路由 admin.Route(r) return r }
后台接口:提供了添加 group 和 wg 表的基本接口,让项目能跑起来
package admin import ( "gw/pkg/admin" "github.com/gin-gonic/gin" ) func Route(r *gin.Engine) { // 路由访问转发的接口 r.POST("/req/add/api", admin.Add) // api 动态生成转发接口的表添加 r.POST("/req/add/group", admin.AddGroup) }
前台接口:动态循环路由组(group),将其配置添加到模糊路由中,为了解决后续增加 wg 表的配置需要重启
package api import ( "fmt" "gw/pkg/api" "gw/library" "gw/pkg/middle" "github.com/gin-gonic/gin" ) func Route(r *gin.Engine) { list, err := library.Group("group") if err != nil { panic(fmt.Sprintf("Api Route Was Wrong Err Was %s", err)) } //动态加载路由,根据mongoDB中的path加载 for _, v := range list { pth := v.Group r.Any(fmt.Sprintf("%s%s", pth, "*action"), api.Run, middle.Body()) } }
执行程序入口:该入口是整个系统的逻辑入口,目前还没想到更好的方式
package api import ( "fmt" "net/http" "time" "gw/conf" "gw/library" "gw/pkg/ds" "gw/pkg/dy" "gw/pkg/fw" "gw/util" "github.com/gin-gonic/gin" ) // 入口函数 func Run(c *gin.Context) { t := time.NewTimer(conf.RequestTimeOut * time.Second) //设置 global var glb G glb.Rch = make(chan string) glb.Ech = make(chan error) go func(c *gin.Context, glb *G) { glb.RequestTime = util.GetTime() //设置请求访问的数据 if err := glb.SetInfo(c); err != nil { glb.Ech <- err return } //容错 decay := dy.Decay{ Open: glb.Md.Decay, DecayTime: glb.Md.DecayTime, Ctx: c, } decayBody := decay.Start() if decayBody != "" { glb.Rch <- decayBody return } //获取要访问的url dns := ds.Dns{ Ds: glb.Md.Dns, Pth: glb.Md.To, Ctx: c, } dns.GetRestUrl() glb.To = dns.To glb.Query = dns.Query //流量检查 flow := fw.Flow{ Path: glb.To, Num: glb.Md.Flow, } if err := flow.Check(); err != nil { glb.Ech <- err return } //发起请求 hp := library.HttpRequest{ Method: glb.Md.Method, To: glb.To, Query: glb.Query, Out: glb.Md.Timeout, CacheTime: glb.Md.CacheTime, } //发起请求 body, err := hp.Http() if err != nil { glb.Ech <- err return } //写入上下文,目前用于容错 c.Set("RequestBody", body) glb.Rch <- body }(c, &glb) select { case rch := <-glb.Rch: c.String(http.StatusOK, rch) case ech := <-glb.Ech: c.String(http.StatusInternalServerError, fmt.Sprintln(ech)) case <-t.C: c.String(http.StatusNotFound, "request time out") } t.Stop() }
从上述代码中可以看到大致的项目设计了,具体功能代码不再单独贴图了,大家可以拿到代码后看一下,项目设计的挺简单的,很方便扩展