wangkaiyue 3 лет назад
Родитель
Сommit
439d4a5c92

+ 53 - 0
README.md

@@ -0,0 +1,53 @@
+# BaseService/gateway
+
+`BaseService/gateway` 剑鱼网关服务。为剑鱼网站商品标准化,提供统一权限校验,资源扣减。
+
+## 网关配置
+
+
+## 
+
+
+## 服务注册与服务发现
+
+服务注册与发现依赖`go.etcd.io/etcd/client/v3`库。
+> 服务注册
+
+注册时向etcd中put `scheme/serverCode@serverAddr` key并设置租期
+- `scheme` 默认为 `etcd:///com.gateway`
+- `serverCode` 为服务code,在系统中需要唯一
+- `serverAddr` 为服务ip+端口
+
+服务注册[例子](https://bp.jydev.jianyu360.cn/BaseService/gateway/src/master/core/node/hellowrold/main.go) 。服务已注册,但服务不可用可能有以下操作*造成。但服务有重试机制,并常识可用节点,不会造成影响。
+```go
+server := g.Server()
+
+// 向网关注册表注册服务。*此步骤应在服务启动后注册
+// NewNode可传入etcd节点,默认http://127.0.0.1:2379
+closeNotify, err := node.NewNode(etcdNode1,etcdNode2...).Register(serverCode, serverPort)
+if err != nil { 
+    panic(err)
+}
+
+go func() {
+    server.Run()
+}()
+
+// 阻塞主进程,接受退出消息。关闭服务,从注册表中删除。
+// kill -9 信号接受不到,*会有2~3秒延迟。
+quit := make(chan os.Signal, 1)
+signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
+<-quit
+closeNotify()
+```
+
+>服务发现
+
+服务发现是网关程序依赖`etcd`中`watch`监听系统`scheme`中所有的服务节点。当有服务启动或关闭时,网关程序能够实时进行服务节点的增加与删除。
+```go
+    //创建节点发现,并持续监听
+    watchNode := node.NewNode(etcdNode1,etcdNodes2,..)
+    go watchNode.NewWatcher(ctx, resolver)
+```
+
+

+ 32 - 3
common/db/db.go

@@ -1,9 +1,11 @@
 package db
 
 import (
+	"app.yhyue.com/moapp/jybase/mongodb"
 	"app.yhyue.com/moapp/jybase/mysql"
 	"app.yhyue.com/moapp/jybase/redis"
 	"database/sql"
+	"github.com/gogf/gf/v2/frame/g"
 	"github.com/gogf/gf/v2/os/gcfg"
 	"github.com/gogf/gf/v2/os/gctx"
 	"log"
@@ -18,17 +20,28 @@ type Mysql struct {
 	MaxOpenConns int     //用于设置最大打开的连接数,默认值为0表示不限制。
 	MaxIdleConns int     //用于设置闲置的连接数。
 }
+type MgoConf struct {
+	Address         string
+	Size            int
+	DbName          string
+	ReplSet         string
+	UserName        string
+	Password        string
+	Collection      string
+	Collection_back string
+}
 
 var GateWatMySql *mysql.Mysql
+var MgoLog mongodb.MongodbSim
 
 // InitDatabases 初始化数据库
 func InitDatabases() {
 	initDbCtx := gctx.New()
-	//初始化redis数据库
-	redisAddr := gcfg.Instance().MustGet(initDbCtx, "databases.redis", "session=127.0.0.1:6379,other=127.0.0.1:6379").String()
+	// 初始化redis数据库
+	redisAddr := g.Cfg().MustGet(initDbCtx, "databases.redis", "session=127.0.0.1:6379,other=127.0.0.1:6379").String()
 	redis.InitRedis(redisAddr)
 	log.Printf("初始化redis完成 %s\n", redisAddr)
-	//初始化mysql数据库
+	// 初始化mysql数据库
 	var mysqlConf Mysql
 	err := gcfg.Instance().MustGet(initDbCtx, "databases.mysql").Scan(&mysqlConf)
 	if err != nil {
@@ -45,4 +58,20 @@ func InitDatabases() {
 	}
 	GateWatMySql.Init()
 	log.Printf("初始化Mysql完成 %+v\n", mysqlConf)
+
+	// 初始化mongodb
+	var mgoConf MgoConf
+	if err := gcfg.Instance().MustGet(initDbCtx, "databases.mogLog").Scan(&mgoConf); err == nil {
+		MgoLog = mongodb.MongodbSim{
+			MongodbAddr: mgoConf.Address,
+			Size:        mgoConf.Size,
+			DbName:      mgoConf.DbName,
+			ReplSet:     mgoConf.ReplSet,
+			UserName:    mgoConf.UserName,
+			Password:    mgoConf.Password,
+		}
+		MgoLog.InitPool()
+		log.Printf("初始化 mongodb log 完成 %+v\n", mgoConf)
+	}
+
 }

+ 1 - 0
core/logs/init.go

@@ -35,6 +35,7 @@ func InitLogs() {
 	GReq = initServerLog(serverLogConfig{
 		commonLogConfig:        logCommon,
 		ServerErrorStack:       gcfg.Instance().MustGet(ctx, "system.log.serverErrorStack", false).Bool(),
+		ServerRequestLogSaveDb: gcfg.Instance().MustGet(ctx, "system.log.serverRequestLogSaveDb", false).Bool(),
 		ServerErrorLogEnabled:  gcfg.Instance().MustGet(ctx, "system.log.serverErrorLogEnabled", false).Bool(),
 		ServerErrorLogPattern:  gcfg.Instance().MustGet(ctx, "system.log.serverErrorLogPattern", "system-{Ymd}.log").String(),
 		ServerAccessLogEnabled: gcfg.Instance().MustGet(ctx, "system.log.serverAccessLogEnabled", false).Bool(),

+ 4 - 3
core/logs/notice.go

@@ -3,13 +3,14 @@ package logs
 import (
 	"bp.jydev.jianyu360.cn/BP/jynsq/gonsq"
 	"encoding/json"
+	"github.com/gogf/gf/v2/os/gctx"
 	"log"
 )
 
 type NoticeConfig struct {
 	IsOpen          bool //是否开启提示
 	IsJsonEncode    bool
-	Address, Toppic string
+	Address, TopPic string
 	Id, Title, Text string
 }
 type Notice struct {
@@ -23,7 +24,7 @@ func newNotice(c NoticeConfig) (n *Notice, err error) {
 	}
 	var producer *gonsq.Producer
 	if c.IsOpen {
-		producer, err = gonsq.NewProducer(c.Address, c.Toppic, c.IsJsonEncode)
+		producer, err = gonsq.NewProducer(c.Address, c.TopPic, c.IsJsonEncode)
 		if err != nil {
 			return
 		}
@@ -42,7 +43,7 @@ func (n *Notice) SendWarnMsg(detail map[string]interface{}) error {
 	if err != nil {
 		return err
 	}
-	log.Println("模拟发送信息----->", string(bs))
+	GInfo.Debugf(gctx.New(), "模拟发送信息----->", string(bs))
 	if err := n.p.Publish(bs); err != nil {
 		log.Println("nsq连接失败", err)
 	}

+ 5 - 0
core/logs/output.go

@@ -14,6 +14,7 @@ import (
 func (s *serverLog) RecordLogAndNotice(r *ghttp.Request, err error) {
 	if !s.Config.ServerAccessLogEnabled && //关闭成功日志
 		!s.Config.ServerErrorLogEnabled && //关闭错误日志
+		!s.Config.ServerRequestLogSaveDb && //关闭保存数据库日志
 		s.Notice == nil { //关闭消息通知
 		return
 	}
@@ -71,6 +72,10 @@ func (s *serverLog) RecordLogAndNotice(r *ghttp.Request, err error) {
 		}
 	}
 
+	if s.Config.ServerRequestLogSaveDb {
+		s.saveLogToDb(handlerCtx, r)
+	}
+
 	if err == nil && s.Config.ServerAccessLogEnabled { //记录成功
 		s.accessLog.Printf(r.Context(), contextDetail)
 	} else if err != nil && s.Config.ServerErrorLogEnabled { //记录异常日志

+ 123 - 0
core/logs/saveDb.go

@@ -0,0 +1,123 @@
+package logs
+
+import (
+	"bp.jydev.jianyu360.cn/BaseService/gateway/common/db"
+	"bp.jydev.jianyu360.cn/BaseService/gateway/core/router"
+	"encoding/json"
+	"github.com/gogf/gf/v2/net/ghttp"
+	"log"
+	"strings"
+	"sync"
+	"time"
+)
+
+var (
+	arr = []map[string]interface{}{}
+	//对map的同步
+	lock = &sync.Mutex{}
+)
+
+//SaveLogTask 定时保存日志
+func (s *serverLog) SaveLogTask() {
+	lock.Lock()
+	if len(arr) >= 1 {
+		tmp := arr
+		arr = make([]map[string]interface{}, 0)
+		go func() {
+			log.Println("timer..save..visit..log", len(tmp))
+			db.MgoLog.SaveBulk("jy_logs", tmp...)
+		}()
+	}
+
+	lock.Unlock()
+	time.AfterFunc(5*time.Minute, s.SaveLogTask)
+}
+
+// saveLogToDb 日志存库
+func (s *serverLog) saveLogToDb(ctx *router.GContext, r *ghttp.Request) {
+	md, _ := json.Marshal(r.Request.Form)
+	m := map[string]interface{}{
+		"ip":        r.GetClientIp(),
+		"refer":     r.Referer(),
+		"mdescribe": string(md),
+		"client":    r.UserAgent(),
+		"os":        getOS(r.UserAgent()),
+		"browse":    getBrowse(r.UserAgent()),
+		"method":    r.Method,
+		"url":       r.URL.String(),
+	}
+	if ctx.Sess.UserId != "" {
+		m["userid"] = ctx.Sess.UserId
+	}
+	if ctx.Sess.NewUid != 0 {
+		m["userid_new"] = ctx.Sess.NewUid
+	}
+	if ctx.Sess.EntId != 0 {
+		m["userid"] = ctx.Sess.EntId
+	}
+
+	timeNow := time.Now()
+	m["date"] = timeNow.Unix()
+	m["year"] = timeNow.Year()
+	m["month"] = timeNow.Month()
+	m["day"] = timeNow.Day()
+	m["hour"] = timeNow.Hour()
+	m["minutes"] = timeNow.Minute()
+
+	lock.Lock()
+	arr = append(arr, m)
+	if len(arr) >= 500 {
+		tmp := arr
+		arr = make([]map[string]interface{}, 0)
+		go func() {
+			log.Println("save..visit..log", len(tmp), db.MgoLog.SaveBulk("jy_gateway_logs", tmp...))
+		}()
+	}
+	lock.Unlock()
+}
+
+// getOS 获取平台类型
+func getOS(useros string) string {
+	osVersion := "其他"
+	if strings.Contains(useros, "NT 6.0") {
+		osVersion = "Windows Vista/Server 2008"
+	} else if strings.Contains(useros, "NT 5.2") {
+		osVersion = "Windows Server 2003"
+	} else if strings.Contains(useros, "NT 5.1") {
+		osVersion = "Windows XP"
+	} else if strings.Contains(useros, "NT 5") {
+		osVersion = "Windows 2000"
+	} else if strings.Contains(useros, "Mac") {
+		osVersion = "Mac"
+	} else if strings.Contains(useros, "Unix") {
+		osVersion = "UNIX"
+	} else if strings.Contains(useros, "Linux") {
+		osVersion = "Linux"
+	} else if strings.Contains(useros, "SunOS") {
+		osVersion = "SunOS"
+	} else if strings.Contains(useros, "NT 6.3") {
+		osVersion = "Window8"
+	} else if strings.Contains(useros, "NT 6.1") {
+		osVersion = "Window7"
+	} else if strings.Contains(useros, "NT 10.0") {
+		osVersion = "Window10"
+	}
+	return osVersion
+}
+
+// getBrowse 获取浏览器类型
+func getBrowse(userbrowser string) string {
+	browserVersion := "其他"
+	if strings.Contains(userbrowser, "MSIE") {
+		browserVersion = "IE"
+	} else if strings.Contains(userbrowser, "Firefox") {
+		browserVersion = "Firefox"
+	} else if strings.Contains(userbrowser, "Chrome") {
+		browserVersion = "Chrome"
+	} else if strings.Contains(userbrowser, "Safari") {
+		browserVersion = "Safari"
+	} else if strings.Contains(userbrowser, "rv:11.0") {
+		browserVersion = "IE11"
+	}
+	return browserVersion
+}

+ 8 - 1
core/logs/serverLogs.go

@@ -24,6 +24,7 @@ func initBaseLog(c *commonLogConfig, fileName string) (l *glog.Logger) {
 type serverLogConfig struct {
 	*commonLogConfig
 	ServerErrorStack       bool   //当Server捕获到异常时是否记录堆栈信息到日志中。默认为true
+	ServerRequestLogSaveDb bool   //请求日志是否保存至数据库。默认false
 	ServerErrorLogEnabled  bool   //是否记录访问异常日志到日志中。默认为true
 	ServerErrorLogPattern  string //访问异常日志文件格式。默认为"error-{Ymd}.log"
 	ServerAccessLogEnabled bool   //是否记录访问日志。默认为false
@@ -57,10 +58,16 @@ func initServerLog(sc serverLogConfig, nc NoticeConfig) *serverLog {
 		log.Println("GNotice nsq通知初始化异常", err)
 	}
 
-	return &serverLog{
+	slog := &serverLog{
 		accessLog: accessLog,
 		errorLog:  errorLog,
 		Config:    sc,
 		Notice:    notice,
 	}
+
+	if sc.ServerRequestLogSaveDb {
+		go slog.SaveLogTask()
+	}
+
+	return slog
 }

+ 21 - 17
core/node/hellowrold/main.go

@@ -15,31 +15,35 @@ func main() {
 
 	var serverCode string = "gatewayDemo"
 	var serverPort int = 8099
-	closeNotify, err := node.NewNode().Register(serverCode, fmt.Sprintf("%d", 8098))
+
+	server := g.Server()
+	server.SetPort(serverPort)
+	server.BindHandler("/gatewayDemo/{page}", func(r *ghttp.Request) {
+		r.Response.Write(map[string]interface{}{
+			"code": 1,
+			"func": r.Get("page"),
+			"param": map[string]interface{}{
+				"name": r.Get("name").String(),
+				"age":  r.Get("age").Int64(),
+				"eId":  r.Get("entId").Int64(),
+				"uId":  r.Get("userId").String(),
+			},
+		})
+	})
+
+	//向网关注册表注册服务。此步骤应在服务启动后注册。服务有重试机制不受影响。
+	//NewNode可传入etcd节点,默认http://127.0.0.1:2379
+	closeNotify, err := node.NewNode().Register(serverCode, fmt.Sprintf("%d", serverPort))
 	if err != nil {
 		panic(err)
 	}
 
 	go func() {
-		server := g.Server()
-		server.SetPort(serverPort)
-		server.BindHandler("/gatewayDemo/{page}", func(r *ghttp.Request) {
-			//r.Response.Header().Set("deductNum", "6")
-			//r.Response.Header().Set("ids", strings.Join(getIdArr(20000), ","))
-			r.Response.Write(map[string]interface{}{
-				"code": 1,
-				"func": r.Get("page"),
-				"param": map[string]interface{}{
-					"name": r.Get("name").String(),
-					"age":  r.Get("age").Int64(),
-					"eId":  r.Get("entId").Int64(),
-					"uId":  r.Get("userId").String(),
-				},
-			})
-		})
 		server.Run()
 	}()
 
+	//阻塞主进程,接受退出消息。关闭服务,从注册表中删除。
+	//kill -9 信号接受不到,会有2~3秒延迟。服务有重试机制不受影响。
 	quit := make(chan os.Signal, 1)
 	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
 	<-quit

+ 1 - 1
core/proxy/loadmodule/interface.go

@@ -16,9 +16,9 @@ type ProxyLoadModule interface {
 	Get(string) (*url.URL, error) //获取节点
 	Add(string) error             //添加节点
 	Del(string) error             //动态添加
-	//ALlNodes() []url.URL          //获取节点内容
 }
 
+// LoadProxyLoadFactory 节点负载模式
 func LoadProxyLoadFactory(value int) ProxyLoadModule {
 	switch ProxyLoadType(value) {
 	case RandomProxyModule: //随机

+ 15 - 35
core/proxy/middleware/filterFuncs.go

@@ -3,21 +3,20 @@ package middleware
 import (
 	"bp.jydev.jianyu360.cn/BaseService/gateway/common"
 	. "bp.jydev.jianyu360.cn/BaseService/gateway/common/gatecode"
-	"bp.jydev.jianyu360.cn/BaseService/gateway/core/logs"
 	"bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/rpc"
 	"bp.jydev.jianyu360.cn/BaseService/gateway/core/router"
-	"bytes"
-	"encoding/json"
 	"github.com/gogf/gf/v2/net/ghttp"
 	"github.com/gogf/gf/v2/os/gcfg"
 	"github.com/gogf/gf/v2/os/gctx"
 	"github.com/gogf/gf/v2/util/gconv"
-	"io/ioutil"
 	"net/http"
 	"strings"
 )
 
 // filterBefore 前置拦截处理
+// step 1:session校验
+// step 2: 账户状态校验
+// step 3: 接口权益校验
 func filterBefore(r *ghttp.Request) error {
 	ctx := router.GetGContext(r.GetCtx())
 	rule := ctx.RouterRule
@@ -34,7 +33,7 @@ func filterBefore(r *ghttp.Request) error {
 
 		//	用户身份注入请求体中
 		if (uCheck || eCheck) && r.Request.Method == http.MethodPost {
-			infusionIdentity(r, ctx.Sess.EntId, ctx.Sess.UserId, ctx.Sess.Phone, rule.AppId)
+			infusionIdentity(r, ctx.Sess, rule.AppId)
 		}
 	}
 
@@ -47,13 +46,15 @@ func filterBefore(r *ghttp.Request) error {
 
 	//校验权益
 	if rule.PowerCheck == 1 {
-		if err := rpc.CheekResourcePower(ctx.Sess.EntId, -1, rule.FuncCode, r.Get("functionCode").String(), rule.AppId); err != nil {
+		if err := rpc.CheckResourcePower(ctx.Sess.EntId, ctx.Sess.NewUid, rule.FuncCode, r.GetHeader("functionCode"), rule.AppId); err != nil {
 			return err
 		}
 	}
 	return nil
 }
 
+// filterAfter 后置扣减逻辑。
+// 同步处理,若扣减异常,接口返回错误信息。
 func filterAfter(r *ghttp.Request) error {
 	ctx := router.GetGContext(r.GetCtx())
 	rule := ctx.RouterRule
@@ -69,7 +70,7 @@ func filterAfter(r *ghttp.Request) error {
 				ids = strings.Split(idsStr, ",")
 			}
 		}
-		if err := rpc.ResourcePowerDeduct(ctx.Sess.EntId, -1, rule.FuncCode, rule.AppId, deductNum, ids); err != nil {
+		if err := rpc.ResourcePowerDeduct(ctx.Sess.EntId, ctx.Sess.NewUid, rule.FuncCode, rule.AppId, deductNum, ids); err != nil {
 			r.SetError(err)
 		}
 	}
@@ -80,32 +81,11 @@ func filterAfter(r *ghttp.Request) error {
 	return nil
 }
 
-// getPowerCheck 是否需要校验
-// 0:否;
-// 其他 xy: x userId 校验 y entId校验 z权益校验,【1需要 0 不需要】
-// 例如 10 校验用户id 不校验entId
-func getPowerCheck(c int) (userIdCheck bool, entIdCheck bool) {
-	userIdCheck = c/10%10 == 1
-	entIdCheck = c/1%10 == 1
-	return
-}
-
-// infusionIdentity 用户身份注入
-func infusionIdentity(r *ghttp.Request, entId int64, userId, phone, appId string) {
-	//body-json请求方式
-	newBody := map[string]interface{}{}
-	logs.GInfo.Debug(r.GetCtx(), "请求内容-req", string(r.GetBody()))
-	_ = json.Unmarshal(r.GetBody(), &newBody)
-	if len(newBody) == 0 {
-		r.Request.Header.Set("Content-Type", "application/json")
-	}
-	newBody["userId"] = userId
-	newBody["entId"] = entId
-	newBody["phone"] = phone
-	newBody["appId"] = appId
-	nb, _ := json.Marshal(newBody)
-	logs.GInfo.Debug(r.GetCtx(), "请求内容-changed", string(nb))
-	r.Request.Body = ioutil.NopCloser(bytes.NewBuffer(nb))
-	r.ContentLength = int64(len(nb))
-	//r.Request.Header.Set("Content-Length", fmt.Sprintf("%d", len(nb)))
+// infusionIdentity 用户身份注入Header
+func infusionIdentity(r *ghttp.Request, sess *router.JySession, appId string) {
+	r.Header.Set("appId", appId)
+	r.Header.Set("userId", sess.UserId)
+	r.Header.Set("entName", sess.EntName)
+	r.Header.Set("entId", gconv.String(sess.EntId))
+	r.Header.Set("phone", sess.Phone)
 }

+ 0 - 10
core/proxy/proxyClient/proxyClient.go

@@ -16,19 +16,9 @@ var transport = &http.Transport{}
 func CreateCustomProxyClient(target *url.URL, errFunc func(http.ResponseWriter, *http.Request, error)) *httputil.ReverseProxy {
 	return &httputil.ReverseProxy{
 		Director: func(req *http.Request) {
-			targetQuery := target.RawQuery
 			req.URL.Scheme = target.Scheme
 			req.URL.Host = target.Host
 			req.URL.Path = singleJoiningSlash(target.Path, req.URL.Path)
-			if targetQuery == "" || req.URL.RawQuery == "" {
-				req.URL.RawQuery = targetQuery + req.URL.RawQuery
-			} else {
-				req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
-			}
-			if _, ok := req.Header["User-Agent"]; !ok {
-				// explicitly disable User-Agent so it's not set to default value
-				req.Header.Set("User-Agent", "")
-			}
 		},
 		Transport: transport,
 		//ModifyResponse: change,

+ 10 - 6
core/proxy/proxyServer.go

@@ -55,34 +55,38 @@ func InitGateWayServer() *ghttp.Server {
 	return gateWayServer
 }
 
-// proxyHandler 网关代理Handler处理,完成所有校验后
+// proxyHandler 网关代理Handler处理
+// 完成所有前置校验后,请求代理服务逻辑
 var proxyHandler = func(r *ghttp.Request) {
 	if r.GetError() != nil {
 		return
 	}
+	// 获取请求上下文内容
 	gCtx := router.GetGContext(r.GetCtx())
-
+	// 请求重试,防止某个服务中断不可用,导致接口不可用。
 	for i := 0; i < errTryTime; i++ {
-		//获取服务地址
+		// 根据负载规则获取服务地址
 		proxyAddr, err := bManager.GetServerAddr(gCtx.RouterRule.MiddleCode, r.GetClientIp())
 		if err != nil {
 			r.SetError(err)
 			return
 		}
-		//代理地址存入ctx中
+		// 代理地址存入上下文ctx中
 		gCtx.ServerAddr = proxyAddr.String()
 		router.UpdateGContext(r, gCtx)
 
+		// 捕获异常,若代理出错,则进行重试
 		var hasErr bool
-
 		errHandel := func(hw http.ResponseWriter, hr *http.Request, err error) {
 			hasErr = true
 			if i == (errTryTime - 1) {
 				r.SetError(NewErrorWithCode(GATEWAY_PROXY_ERR, fmt.Sprintf("代理异常:%s err:%v \n", gCtx.ServerAddr, err.Error())))
 			}
 		}
-
+		// 代理请求
 		proxyClient.CreateCustomProxyClient(proxyAddr, errHandel).ServeHTTP(r.Response.ResponseWriter, r.Request)
+
+		// 未捕获到请求,标识请求成功
 		if !hasErr {
 			return
 		}

+ 2 - 2
core/proxy/rpc/resourceCenter.go

@@ -23,13 +23,13 @@ func initResourceCenterRpc() {
 	}))
 }
 
-// CheekResourcePower 校验账户是否有对应权益
+// CheckResourcePower 校验账户是否有对应权益
 // eid 企业id
 // uId 新用户id;非mongodb中user表id
 // funcCode 业务代码
 // reqFuncCode 	 通用结构&&需要校验权限则先判断此接口是否有此functionCode的方法
 // appid 平台标识
-func CheekResourcePower(eId, uId int64, funcCodeRule, reqFuncCode, Appid string) error {
+func CheckResourcePower(eId, uId int64, funcCodeRule, reqFuncCode, Appid string) error {
 	funcCode := funcCodeRule
 	funcCodeArr := strings.Split(funcCodeRule, ",")
 	if reqFuncCode != "" || len(funcCodeArr) > 1 {

+ 5 - 6
core/router/ctx.go

@@ -20,13 +20,12 @@ func UpdateGContext(r *ghttp.Request, GCtx *GContext) {
 }
 
 // GetGContext 获取上下文GContext
-func GetGContext(ctx context.Context) *GContext {
+func GetGContext(ctx context.Context) (gCtx *GContext) {
+	gCtx = &GContext{}
 	value := ctx.Value(GContextKey)
 	if value == nil {
-		return nil
+		return
 	}
-	if GCtx, ok := value.(*GContext); ok {
-		return GCtx
-	}
-	return nil
+	gCtx, _ = value.(*GContext)
+	return
 }

+ 7 - 2
core/router/manager.go

@@ -16,18 +16,21 @@ type Manager struct {
 }
 
 // InitRouterManager 初始化系统代理路由
+// 支持完全匹配和正则匹配
 func InitRouterManager() (*Manager, error) {
 	res := db.GateWatMySql.Query("SELECT status,middleground_code,url,function_code,check_sess,check_power,check_auth,check_status,check_blacklist,timeout,remark,appid,deduct_source FROM front_proxy")
 	if res == nil || len(*res) == 0 {
 		return nil, fmt.Errorf("未发现可用路由")
 	}
+	// 初始化 routerManager
 	routerManager := &Manager{
 		eqRouters:   make(map[string]*Router),
 		regexRouter: make(map[*regexp.Regexp]*Router),
 	}
+
 	for _, row := range *res {
+		// 获取路由信息
 		router := gconv.String(row["url"])
-
 		routerRule := &Router{
 			Status:       gconv.Int(row["status"]),
 			SessCheck:    gconv.Int(row["check_sess"]),
@@ -44,6 +47,7 @@ func InitRouterManager() (*Manager, error) {
 			Remark:       gconv.String(row["remark"]),
 		}
 
+		// 判断路由匹配方式是完全匹配还是正则匹配 (此处逻辑参考x-web框架)
 		if regexp.QuoteMeta(router) == router {
 			routerManager.eqRouters[router] = routerRule
 		} else {
@@ -58,6 +62,7 @@ func InitRouterManager() (*Manager, error) {
 }
 
 // GetRouterRule 获取路由规则
+// 根据用户请求地址匹配路由规则,优先绝对匹配后用正则匹配。
 func (m *Manager) GetRouterRule(url string) (*Router, error) {
 	routerRule, exists := m.eqRouters[url]
 	if !exists {
@@ -70,7 +75,7 @@ func (m *Manager) GetRouterRule(url string) (*Router, error) {
 	if routerRule == nil {
 		return nil, NewErrorWithCode(GATEWAY_ROUTER_NOTFIND, fmt.Sprintf("未找到请求地址%s,请检查是否注册到数据库\n", url))
 	}
-
+	// 路由状态判断
 	if routerRule.Status != 1 {
 		return nil, NewErrorWithCode(GATEWAY_ROUTER_UPHOLD, fmt.Sprintf("接口状态:%d\n", routerRule.Status))
 	}

+ 8 - 4
core/router/session.go

@@ -17,10 +17,12 @@ const (
 
 // JySession 剑鱼程序SESSION获取
 type JySession struct {
-	UserId string // 上下文用户信息
-	EntId  int64  // 当前企业id
-	Phone  string // 手机号
-	Data   g.Map  // 当前Session管理对象
+	UserId  string // 上下文用户信息
+	NewUid  int64  // 新用户id
+	EntId   int64  // 当前企业id
+	EntName string // 当前企业名称
+	Phone   string // 手机号
+	Data    g.Map  // 当前Session管理对象
 }
 
 // GetJySession 获取剑鱼程序session内容
@@ -56,7 +58,9 @@ func InitJySessionContext(r *ghttp.Request) (jSession *JySession, err error) {
 	err = json.Unmarshal(*bs, &data)
 	jSession.Phone, _ = data["phone"].(string)
 	jSession.UserId, _ = data["userId"].(string)
+	jSession.EntName, _ = data["entName"].(string)
 	jSession.EntId = gconv.Int64(data["entId"])
+	jSession.NewUid = gconv.Int64(data["userId_new"])
 	jSession.Data = data
 	return
 }

+ 10 - 1
etc/config.yaml

@@ -43,6 +43,14 @@ databases:
     maxOpenConns: 5
     maxIdleConns: 5
 
+  # mongo 日志配置
+  mogLog:
+    address: 192.168.3.206:27090
+    size: 5
+    dbName: qfw
+    replSet:
+    userName: admin
+    password: 123456
 
 # 系统配置
 system:
@@ -60,9 +68,10 @@ system:
   log:
     path: ./logs                                # 系统日志默认文件默认报错路径。默认为./logs
     debug: false                                # 是否打印调试信息。默认false
-    stdout: false                               # 是否输出到控制台。默认false
+    stdout: true                                # 是否输出到控制台。默认false
     systemLogPattern: system-{Ymd}.log          # 日志文件格式。默认为"system-{Ymd}.log"
     serverErrorStack: false                     # 当Server捕获到异常时是否记录堆栈信息到日志中。默认为true
+    serverRequestLogSaveDb: true                # 请求日志是否保存至数据库。默认false
     serverErrorLogEnabled: true                 # 是否记录异常日志信息到日志中。默认为true
     serverErrorLogPattern: error-{Ymd}.log      # 异常错误日志文件格式。默认为"error-{Ymd}.log"
     serverAccessLogEnabled: true                # 是否记录访问日志。默认为false

+ 11 - 0
go.sum

@@ -79,6 +79,7 @@ github.com/alicebob/miniredis/v2 v2.17.0/go.mod h1:gquAfGbzn92jvtrSC69+6zZnwSODV
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
+github.com/aws/aws-sdk-go v1.35.20 h1:Hs7x9Czh+MMPnZLQqHhsuZKeNFA3Vuf7pdy2r5QlVb0=
 github.com/aws/aws-sdk-go v1.35.20/go.mod h1:tlPOdRjfxPBpNIwqDj61rmsnA85v9jc0Ps9+muhnW+k=
 github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -181,6 +182,7 @@ github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
 github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
 github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
@@ -318,7 +320,9 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
 github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
+github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@@ -339,6 +343,7 @@ github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0Lh
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
 github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -485,13 +490,17 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
 github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
 github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
 github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
 github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM=
+github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
 github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
+github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc h1:n+nNi93yXLkJvKwXNP9d55HC7lGK4H/SRcwB5IaUZLo=
 github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
+github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
 github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -509,6 +518,7 @@ go.etcd.io/etcd/client/pkg/v3 v3.5.2 h1:4hzqQ6hIb3blLyQ8usCU4h3NghkqcsohEQ3o3Vet
 go.etcd.io/etcd/client/pkg/v3 v3.5.2/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
 go.etcd.io/etcd/client/v3 v3.5.2 h1:WdnejrUtQC4nCxK0/dLTMqKOB+U5TP/2Ya0BJL+1otA=
 go.etcd.io/etcd/client/v3 v3.5.2/go.mod h1:kOOaWFFgHygyT0WlSmL8TJiXmMysO/nNUlEsSsN6W4o=
+go.mongodb.org/mongo-driver v1.5.0 h1:REddm85e1Nl0JPXGGhgZkgJdG/yOe6xvpXUcYK5WLt0=
 go.mongodb.org/mongo-driver v1.5.0/go.mod h1:boiGPFqyBs5R0R5qf2ErokGRekMfwn+MqKaUyHs7wy0=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
@@ -650,6 +660,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=

+ 5 - 5
main.go

@@ -10,13 +10,13 @@ import (
 )
 
 func init() {
-	g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("./etc/config.yaml")
-	logs.InitLogs()         // 初始化日志组件
-	rpc.InitBaseServerRpc() // 初始化rpc服务连接
-	db.InitDatabases()      // 初始化数据库
+	g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetFileName("./etc/config.yaml") //设置配置文件
+	logs.InitLogs()                                                           // 初始化日志组件
+	rpc.InitBaseServerRpc()                                                   // 初始化rpc服务连接
+	db.InitDatabases()                                                        // 初始化数据库
 }
 
 func main() {
-	//网关服务
+	//初始化网关服务并启动服务
 	proxy.InitGateWayServer().Run()
 }