package http import ( "fmt" "io/ioutil" "net/http" "time" "git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/env" "git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/env/config" "git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/loadbalance" "git.wishpal.cn/wishpal_ironfan/xframe/component/agollo/utils" "git.wishpal.cn/wishpal_ironfan/xframe/component/logger" "github.com/pkg/errors" ) var ( //for on error retry onErrorRetryInterval = 2 * time.Second //2s connectTimeout = 1 * time.Second //1s //max retries connect apollo maxRetries = 5 ) // CallBack 请求回调函数 type CallBack struct { SuccessCallBack func([]byte) (interface{}, error) NotModifyCallBack func() error } // Request 建立网络请求 func Request(requestURL string, connectionConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) { client := &http.Client{} //如有设置自定义超时时间即使用 if connectionConfig != nil && connectionConfig.Timeout != 0 { client.Timeout = connectionConfig.Timeout } else { client.Timeout = connectTimeout } retry := 0 var responseBody []byte var err error var res *http.Response var retries = maxRetries if connectionConfig != nil && !connectionConfig.IsRetry { retries = 1 } for { retry++ if retry > retries { break } res, err = client.Get(requestURL) if res == nil || err != nil { logger.Errorf("Connect Apollo Server Fail,url:%s,Error:%s", requestURL, err) // if error then sleep time.Sleep(onErrorRetryInterval) continue } //not modified break switch res.StatusCode { case http.StatusOK: responseBody, err = ioutil.ReadAll(res.Body) if err != nil { logger.Errorf("Connect Apollo Server Fail,url:%s,Error:", requestURL, err) // if error then sleep time.Sleep(onErrorRetryInterval) continue } if callBack != nil && callBack.SuccessCallBack != nil { return callBack.SuccessCallBack(responseBody) } return nil, nil case http.StatusNotModified: //log.Info("Config Not Modified, requestURL = %v", requestURL) if callBack != nil && callBack.NotModifyCallBack != nil { return nil, callBack.NotModifyCallBack() } return nil, nil default: logger.Errorf("Connect Apollo Server Fail,url:%s,StatusCode:%s", requestURL, res.StatusCode) err = errors.New("connect Apollo Server Fail") // if error then sleep time.Sleep(onErrorRetryInterval) continue } } logger.Errorln("Over Max Retry Still Error,Error:", err) if err != nil { err = errors.New("over Max Retry Still Error") } return nil, err } // RequestRecovery 可以恢复的请求 func RequestRecovery(appConfig *config.AppConfig, connectConfig *env.ConnectConfig, callBack *CallBack) (interface{}, error) { format := "%s%s" var err error var response interface{} for { host := loadBalance(appConfig) if host == "" { return nil, err } requestURL := fmt.Sprintf(format, host, connectConfig.URI) response, err = Request(requestURL, connectConfig, callBack) if err == nil { return response, err } env.SetDownNode(host) } } // 链接分为直连server和非直连。 // 非直连的情况下会通过配置中的ip访问到metaserver(类似于zookeeper),从metaserver中获取数据。只有当非直连失败的情况下才可能使用直连 func loadBalance(appConfig *config.AppConfig) string { if !appConfig.IsConnectDirectly() { return appConfig.GetHost() } serverInfo := loadbalance.GetLoadBalance().Load(env.GetServers()) if serverInfo == nil { return utils.Empty } return serverInfo.HomepageURL }