年尾這幾天自己研究並開發了一個基於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()
}
從上述代碼中可以看到大致的項目設計了,具體功能代碼不再單獨貼圖了,大家可以拿到代碼后看一下,項目設計的挺簡單的,很方便擴展
