139 lines
3.5 KiB
Go
Executable File
139 lines
3.5 KiB
Go
Executable File
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
|
||
}
|