标签:执行函数 max message == close parser 使用 初始化 rom
service1拥有接口 :
GET user/{user_id}
POST user/add
service2调用service1的接口获取数据
1.创建客户端
//定义客户端结构体 type SimpleClient struct { Client HTTPRequest *http.Request //用于返回执行时的request,直接设值无效。引用时注意做非空检查。 HTTPResponse *http.Response //用于返回执行结果。引用时注意做非空检查。 }
//ClientConfig 客户端属性配置
type ClientConfig struct {
RequestID string
EndPointURLToken string //URL Token
OperationName string //链路追踪名或调用函数名
Timeout int //单位为秒
NumMaxRetries int //最大重试次数
RetryMaxTimeDuration time.Duration //总计重试时间 ExpireTime
TraceOption *TraceOption //追踪打印属性
IsExternalURL bool //数据脱敏,默认为FALSE,是否为调用对外api,如是,则不在header的UserAgent中带上内网ip.
IsRESTStatusCode bool //RESTFulAPI风格,使用状态码来表示资源态.
}
//Client 客户端
type Client struct {
ctx context.Context
HTTPClient *http.Client
CustomHeader http.Header
CustomCookie *http.Cookie
EndPointURL string
ClientConfig
}
//客户端对象构造 func NewSimpleClient(ctx context.Context, url string, configs ...ClientConfig) *SimpleClient { c := &SimpleClient{} c.Client.ctx = ctx c.EndPointURL = url //初始化HTTPClient if len(configs) > 0 { for _, cf := range configs { c.ClientConfig = cf } if c.ClientConfig.Timeout <= 0 { c.ClientConfig.Timeout = 60 } } else {
//默认配置 c.ClientConfig.NumMaxRetries = 5 c.ClientConfig.RetryMaxTimeDuration = _MaxRetryTimeDuration c.ClientConfig.Timeout = 60 } if c.ClientConfig.TraceOption == nil { c.ClientConfig.TraceOption = &TraceOption{} } if c.ClientConfig.OperationName != "" { c.OperationName = c.ClientConfig.OperationName } else { c.OperationName = c.EndPointURL } c.HTTPClient = GetHTTPClient(c.ClientConfig.Timeout) //初始化HTTP Header c.CustomHeader = http.Header{} c.initCustomHeader() // c.HTTPRequest = &http.Request{Header: http.Header{}} c.HTTPRequest = &http.Request{Header: c.CustomHeader} return c }
2.GET请求 //Get 发出Get请求 func (sc *SimpleClient) Get() ([]byte, error) { defer func() { if errPainc := recover(); errPainc != nil { stack := strings.Join(strings.Split(string(debug.Stack()), "\n")[2:], "\n") logger.Error("[Get] - stack errPainc:", errPainc) err := fmt.Errorf("[Get] recover stack::%s", stack) logger.Error("stack:", err) } }() sc.addHeaderRequestID() return sc.callGet() } //addHeaderRequestID 设置HTTP Header中的RequestID func (c *Client) addHeaderRequestID() { if c.CustomHeader.Get(HeaderXKlookRequestID) != "" { return } if c.ClientConfig.RequestID == "" { c.ClientConfig.RequestID = utils.RequestIDFromContext(c.ctx) } c.CustomHeader.Add(HeaderXKlookRequestID, c.ClientConfig.RequestID) } func (sc *SimpleClient) callGet() ([]byte, error) { startTime := time.Now() sc.HTTPRequest, sc.HTTPResponse = nil, nil if sc.EndPointURL == "" { return nil, NewRequestErrorV1(sc.RequestID, sc.EndPointURL, "EndPointURL为空.") } client := sc.GetHTTPClient() var err1 error req, err := http.NewRequest("GET", sc.EndPointURL, nil) if err != nil { err1 = fmt.Errorf(" http.NewRequest发生异常. err:%s 耗时:%s ", err, time.Since(startTime)) return nil, NewRequestErrorV1(sc.RequestID, sc.EndPointURL, err1.Error()) } //设置HTTP Header copyHTTPHeader(req, sc.CustomHeader) if sc.CustomCookie != nil { //设置HTTP.Cookie req.AddCookie(sc.CustomCookie) } //如果是发给第三方的请求 req.Header.Set(HeaderUserAgent, _DefaultUserAgent) sc.HTTPRequest = req resp, err := client.Do(req) if err != nil { err1 = fmt.Errorf("client.Do发生异常. err:%s 耗时:%s", err, time.Since(startTime)) return nil, NewRequestErrorV2(sc.RequestID, sc.EndPointURL, err1.Error(), GetHTTPHeaderString(req)) } sc.HTTPResponse = resp statusCode := resp.StatusCode //需要记录每一次的Header信息 if sc.ClientConfig.TraceOption.RequestHeader { logger.Info(sc.RequestID, " url:", sc.EndPointURL, " ", GetHTTPHeaderString(req), " statusCode:", statusCode) } //RESTFul API常用HTTP状态码来区分状态,然后Body返回状态详情.此时,状态码为非200也是对的. if !sc.IsRESTStatusCode { if statusCode != http.StatusOK { msg := fmt.Sprintf("%s url:%s statusCode:%d %s", sc.RequestID, sc.EndPointURL, statusCode, GetHTTPHeaderString(req)) if resp.Body != nil { respBody, err2 := ioutil.ReadAll(resp.Body) if err2 != nil { msg += " 且读取RespBody发生异常:" + err2.Error() } else { msg += " RespBody:" + string(respBody) } } logger.Info(msg) if statusCode >= 400 && statusCode <= 505 { err1 = fmt.Errorf("对方服务出现异常状态码. 耗时:%s", time.Since(startTime)) } else { //如302之类 err1 = fmt.Errorf("对方服务返回非StatusOK状态码. 耗时:%s", time.Since(startTime)) } resp.Body.Close() return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } } if resp.Body == nil { resp.Body.Close() return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, "resp.Body为空.", statusCode, GetHTTPHeaderString(req)) } respBody, err := ioutil.ReadAll(resp.Body) if err != nil { if err == io.EOF { err1 = fmt.Errorf("resp.Body已读到EOF. err:%s 耗时:%s", err, time.Since(startTime)) } else { err1 = fmt.Errorf("ioutil.ReadAll读取发生异常. err:%s 耗时:%s", err, time.Since(startTime)) } resp.Body.Close() return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } resp.Body.Close() if sc.ClientConfig.TraceOption.RespBody { //记录返回包体 logger.Info(sc.RequestID, " url:", sc.EndPointURL, " RespBody:", string(respBody)) } // //IsRESTFulStatusCode 解析例子 // retErr, ok := err.(*rest.RequestError) // if ok { // t.Log(" \nStatusCode:", retErr.StatusCode(), "\nerr:", retErr.ErrMessage()) // } // if sc.IsRESTStatusCode && statusCode != http.StatusOK { //当为REST风格,且状态码不为200时,返回Body,及Error,调用方可从Error中取得返回状态码 return respBody, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, "", statusCode, GetHTTPHeaderString(req)) } return respBody, nil }
3.POST请求 //PostAndParseResult 发出Post请求,并得到标准化的结构体 func (sc *SimpleClient) PostAndParseResult(body []byte) (*KLResultJSON, error) { defer func() { if errPainc := recover(); errPainc != nil { stack := strings.Join(strings.Split(string(debug.Stack()), "\n")[2:], "\n") logger.Error("[PostAndParseResult] - stack errPainc:", errPainc) err := fmt.Errorf("[PostAndParseResult] recover stack::%s", stack) logger.Error("stack:", err) } }() sc.addHeaderRequestID() body, err := sc.callPost(body) if err != nil { return nil, err } return ParseResultJSON(body) } func (sc *SimpleClient) callPost(body []byte) ([]byte, error) { return sc.callHTTPUpdateRequest("POST", body) } //callHTTPUpdateRequest post/put执行函数实现 func (sc *SimpleClient) callHTTPUpdateRequest(httpMetchod string, body []byte) ([]byte, error) { startTime := time.Now() if sc.EndPointURL == "" { return nil, NewRequestErrorV1(sc.RequestID, sc.EndPointURL, "EndPointURL为空.") } if httpMetchod != "DELETE" && body == nil { return nil, NewRequestErrorV1(sc.RequestID, sc.EndPointURL, "body为空.") } sc.HTTPRequest, sc.HTTPResponse = nil, nil client := sc.GetHTTPClient() if sc.ClientConfig.TraceOption.RequestBody { logger.Info(sc.RequestID, " url:", sc.EndPointURL, " RequestBody:", string(body)) } var err, err1 error var req *http.Request if httpMetchod == "DELETE" { req, err = http.NewRequest(httpMetchod, sc.EndPointURL, nil) } else { req, err = http.NewRequest(httpMetchod, sc.EndPointURL, bytes.NewReader(body)) } if err != nil { err1 = fmt.Errorf("http.NewRequest发生异常. err:%s 耗时:%s ", err, time.Since(startTime)) return nil, NewRequestErrorV1(sc.RequestID, sc.EndPointURL, err1.Error()) } //设置HTTP Header copyHTTPHeader(req, sc.CustomHeader) if sc.CustomCookie != nil { //设置HTTP.Cookie req.AddCookie(sc.CustomCookie) } req.Header.Set(HeaderUserAgent, _DefaultUserAgent) sc.HTTPRequest = req resp, err := client.Do(req) if err != nil { err1 = fmt.Errorf("client.Do发生异常. err:%s 耗时:%s ", err.Error(), time.Since(startTime)) return nil, NewRequestErrorV2(sc.RequestID, sc.EndPointURL, err1.Error(), GetHTTPHeaderString(req)) } defer resp.Body.Close() sc.HTTPResponse = resp statusCode := resp.StatusCode //需要记录每一次的Header信息 if sc.ClientConfig.TraceOption.RequestHeader { logger.Info(sc.RequestID, " url:", sc.EndPointURL, " ", GetHTTPHeaderString(req), " statusCode:", statusCode, " status:", resp.Status) } //RESTFul API常用HTTP状态码来区分状态,然后Body返回状态详情.此时,状态码为非200也是对的. if !sc.IsRESTStatusCode { if statusCode != http.StatusOK { msg := fmt.Sprintf("%s url:%s statusCode:%d %s", sc.RequestID, sc.EndPointURL, statusCode, GetHTTPHeaderString(req)) if resp.Body != nil { respBody, err2 := ioutil.ReadAll(resp.Body) if err2 != nil { msg += " 且读取RespBody发生异常:" + err2.Error() } else { msg += " RespBody:" + string(respBody) } } logger.Info(msg) if statusCode >= 400 && statusCode <= 505 { err1 = fmt.Errorf("对方服务出现异常. 耗时:%s", time.Since(startTime)) return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } // 在Post情况下,当状态码不为StatusOK时,算执行失败。 err1 = fmt.Errorf("返回的状态码非StatusOK. 耗时:%s", time.Since(startTime)) return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } } if resp.Body == nil { err1 = fmt.Errorf("resp.Body为空. err:%v 耗时:%s", err, time.Since(startTime)) return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } respBody, err := ioutil.ReadAll(resp.Body) if err != nil { if err == io.EOF { err1 = fmt.Errorf("resp.Body已读到EOF. err:%s 耗时:%s", err, time.Since(startTime)) } else { err1 = fmt.Errorf("ioutil.ReadAll读取发生异常. err:%s 耗时:%s", err, time.Since(startTime)) } return nil, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, err1.Error(), statusCode, GetHTTPHeaderString(req)) } if sc.ClientConfig.TraceOption.RespBody { logger.Info(sc.RequestID, " url:", sc.EndPointURL, " RespBody:", string(respBody)) } // //IsRESTFulStatusCode 解析例子 // retErr, ok := err.(*rest.RequestError) // if ok { // t.Log(" \nStatusCode:", retErr.StatusCode(), "\nerr:", retErr.ErrMessage()) // } // if sc.IsRESTStatusCode && statusCode != http.StatusOK { //当为REST风格,且状态码不为200时,返回Body,及Error,调用方可从Error中取得返回状态码 return respBody, NewRequestErrorV3(sc.RequestID, sc.EndPointURL, "", statusCode, GetHTTPHeaderString(req)) } return respBody, nil }
标签:执行函数 max message == close parser 使用 初始化 rom
原文地址:http://www.cnblogs.com/fwdqxl/p/7396498.html