package proxy import ( "fmt" "net/http" "net/url" "time" log "app.yhyue.com/moapp/jylog" . "bp.jydev.jianyu360.cn/BaseService/gateway/common/gatecode" "bp.jydev.jianyu360.cn/BaseService/gateway/core/node" "bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/broker" "bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/broker/outServer" "bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/middleware" "bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/proxyClient" "bp.jydev.jianyu360.cn/BaseService/gateway/core/proxy/vars" "bp.jydev.jianyu360.cn/BaseService/gateway/core/router" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/net/gtrace" "github.com/gogf/gf/v2/os/gcfg" "github.com/gogf/gf/v2/os/gctx" ) var routerManager *router.Manager const errTryTime = 3 //错误尝试 // InitGateWayServer 初始化网关服务 func InitGateWayServer(initCtx gctx.Ctx) *ghttp.Server { initCtx, span := gtrace.NewSpan(initCtx, "InitGateWayServer") defer span.End() //创建节点,并持续观察节点变化 watchNode := node.NewNode(gcfg.Instance().MustGet(initCtx, "system.etcdListen", nil).Strings()...) go watchNode.NewWatcher(initCtx, vars.BManager) //初始化可访问路由 var err error routerManager, err = router.InitRouterManager() if err != nil { log.WithContext(initCtx).Errorln(err) } //初始化外部服务 sussBiServer, err := outServer.InitSussBi(gcfg.Instance().MustGet(initCtx, "outServer.sussbi", nil).Map()) if err != nil { log.WithContext(initCtx).Infoln(err) } else { vars.BManager.RegisterOutServer(sussBiServer.Url, sussBiServer) } gateWayServer := g.Server() //关闭系统自带请求日志 gateWayServer.SetLogger(g.Log()) gateWayServer.SetErrorLogEnabled(false) //注册中间件 gateWayServer.Use(middleware.ErrorHandler) //错误拦截 gateWayServer.Use(func(r *ghttp.Request) { r.SetError(routerManager.InfusionContext(r)) //context注入全局信息 r.Middleware.Next() }) gateWayServer.Use(middleware.FilterPolyHandler) //反爬虫策略 gateWayServer.Use(middleware.FilterHandler) //权限过滤 //加载代理客户端 proxyClient.ReLoadClient() //注册代理 gateWayServer.BindHandler("POST:/*", proxyHandler) //接口代理 gateWayServer.BindHandler("GET:/*", proxyHandler) //页面代理 gateWayServer.AddStaticPath("/antiRes", "./resources/antiRes") //静态资源 return gateWayServer } // proxyHandler 网关代理Handler处理 // 完成所有前置校验后,请求代理服务逻辑 var proxyHandler = func(r *ghttp.Request) { _, span := gtrace.NewSpan(r.Context(), "proxyHandler") defer span.End() if r.GetError() != nil { return } // 获取请求上下文内容 gCtx := router.GetGContext(r.GetCtx()) // 请求重试,防止某个服务中断不可用,导致接口不可用。 for i := 0; i < errTryTime; i++ { var proxyAddr *url.URL var err error var changeFunc func(resp *http.Response) error if gCtx.RouterRule.IsOutServer { //外部服务直接获取 proxyAddr, err = vars.BManager.GetOutSeverAutoLogin(gCtx.RouterRule.MiddleCode, r) changeFunc = broker.UnLoginSetErr //当未登录时,通过处罚异常尝试重新加载 } else { // 从etcd注册的地址,根据负载规则获取服务地址 proxyAddr, err = vars.BManager.GetServerAddr(gCtx.RouterRule.MiddleCode, r.GetClientIp()) cf := r.GetCtxVar("changeFunc") if function, ok := cf.Val().(func(resp *http.Response) error); ok { changeFunc = function } } if err != nil { r.SetError(err) return } // 代理地址存入上下文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 err.Error() == "context canceled" { return } if i == (errTryTime - 1) { r.SetError(NewErrorWithCode(GATEWAY_PROXY_ERR, fmt.Sprintf("代理异常:%s err:%v \n", gCtx.ServerAddr, err.Error()))) } log.WithContext(r.Context()).Error("ErrorHandler ", err) } // 代理请求 proxyClient.CreateCustomProxyClient(proxyAddr, errHandel, changeFunc).ServeHTTP(r.Response.ResponseWriter, r.Request) if gCtx.RouterRule.IsOutServer { //检测外部服务登录状态是否过期 if hasErr || vars.BManager.CheckOutSeverLoginOut(gCtx.RouterRule.MiddleCode, r) { if err := vars.BManager.OutSeverLoginIn(gCtx.RouterRule.MiddleCode); err != nil { log.WithContext(r.GetCtx()).Errorf("%s 外部服务自动登录异常 %v \n", gCtx.RouterRule.MiddleCode, err) } else { log.WithContext(r.GetCtx()).Errorf("%s 外部服务自动登录成功 \n", gCtx.RouterRule.MiddleCode) } } } // 未捕获到请求,标识请求成功 if !hasErr { return } time.Sleep(time.Millisecond * 500) } }