From b0d6f3bd2fb7f033c570c0782259a642167fae65 Mon Sep 17 00:00:00 2001 From: holooooo <844082183@qq.com> Date: Fri, 21 May 2021 16:56:52 +0800 Subject: [PATCH] temp --- client/httplib/client_option_test.go | 12 ----- client/httplib/error_code.go | 8 ++++ client/httplib/httpclient.go | 69 +++++++++++++++++++++++----- client/httplib/httpclient_test.go | 12 ----- client/httplib/httplib.go | 19 ++++---- 5 files changed, 75 insertions(+), 45 deletions(-) diff --git a/client/httplib/client_option_test.go b/client/httplib/client_option_test.go index 9efeaa24..3c9df88a 100644 --- a/client/httplib/client_option_test.go +++ b/client/httplib/client_option_test.go @@ -34,18 +34,6 @@ func (r *respCarrier) SetHttpResponse(resp *http.Response) { r.Resp = resp } -func (r *respCarrier) SetBytes(bytes []byte) { - r.bytes = bytes -} - -func (r *respCarrier) Bytes() []byte { - return r.bytes -} - -func (r *respCarrier) String() string { - return string(r.bytes) -} - func TestOption_WithEnableCookie(t *testing.T) { client, err := NewClient("test", "http://httpbin.org/", WithEnableCookie(true)) diff --git a/client/httplib/error_code.go b/client/httplib/error_code.go index bd349a34..177419ad 100644 --- a/client/httplib/error_code.go +++ b/client/httplib/error_code.go @@ -124,3 +124,11 @@ Make sure that: 1. You pass valid structure pointer to the function; 2. The body is valid YAML document `) + +var UnmarshalResponseToObjectFailed = berror.DefineCode(5001011, moduleName, + "UnmarshalResponseToObjectFailed", ` +Beego trying to unmarshal response's body to structure but failed. +There are several cases that cause this error: +1. You pass valid structure pointer to the function; +2. The body is valid json, Yaml or XML document +`) diff --git a/client/httplib/httpclient.go b/client/httplib/httpclient.go index 69aaa286..ecd557a4 100644 --- a/client/httplib/httpclient.go +++ b/client/httplib/httpclient.go @@ -15,6 +15,9 @@ package httplib import ( + "bytes" + "io" + "io/ioutil" "net/http" ) @@ -27,17 +30,32 @@ type Client struct { Setting BeegoHTTPSettings } -// If value implement this interface. http.response will saved by SetHttpResponse +// HttpResponseCarrier If value implement HttpResponseCarrier. http.Response will pass to SetHttpResponse type HttpResponseCarrier interface { SetHttpResponse(resp *http.Response) } -// If value implement this interface. bytes of http.response will saved by SetHttpResponse -type ResponseBytesCarrier interface { - // Cause of when user get http.response, the body stream is closed. So need to pass bytes by +// HttpBodyCarrier If value implement HttpBodyCarrier. http.Response.Body will pass to SetReader +type HttpBodyCarrier interface { + SetReader(r *io.ReadCloser) +} + +// HttpBytesCarrier If value implement HttpBytesCarrier. +// All the byte in http.Response.Body will pass to SetBytes +type HttpBytesCarrier interface { SetBytes(bytes []byte) } +// HttpStatusCarrier If value implement HttpStatusCarrier. http.Response.StatusCode will pass to SetStatusCode +type HttpStatusCarrier interface { + SetStatusCode(status int) +} + +// HttpHeaderCarrier If value implement HttpHeaderCarrier. http.Response.Header will pass to SetHeader +type HttpHeadersCarrier interface { + SetHeader(header map[string][]string) +} + // NewClient return a new http client func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, error) { res := &Client{ @@ -67,18 +85,47 @@ func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error if err != nil { return err } - if carrier, ok := (value).(HttpResponseCarrier); ok { - (carrier).SetHttpResponse(resp) - } - if carrier, ok := (value).(ResponseBytesCarrier); ok { - bytes, err := req.Bytes() + + switch carrier := value.(type) { + case HttpResponseCarrier: + b, err := req.Bytes() if err != nil { return err } - (carrier).SetBytes(bytes) + resp.Body = ioutil.NopCloser(bytes.NewReader(b)) + carrier.SetHttpResponse(resp) + fallthrough + case HttpBodyCarrier: + b, err := req.Bytes() + if err != nil { + return err + } + reader := ioutil.NopCloser(bytes.NewReader(b)) + carrier.SetReader(&reader) + fallthrough + case HttpBytesCarrier: + b, err := req.Bytes() + if err != nil { + return err + } + carrier.SetBytes(b) + fallthrough + case HttpStatusCarrier: + resp, err := req.Response() + if err != nil { + return err + } + carrier.SetStatusCode(resp.StatusCode) + fallthrough + case HttpHeadersCarrier: + resp, err := req.Response() + if err != nil { + return err + } + carrier.SetHeader(resp.Header) } - return req.ResponseForValue(value) + return req.ToValue(value) } // Get Send a GET request and try to give its result value diff --git a/client/httplib/httpclient_test.go b/client/httplib/httpclient_test.go index f006f18f..4a0ae843 100644 --- a/client/httplib/httpclient_test.go +++ b/client/httplib/httpclient_test.go @@ -55,18 +55,6 @@ func (s *slideSshowResponse) SetHttpResponse(resp *http.Response) { s.Resp = resp } -func (s *slideSshowResponse) SetBytes(bytes []byte) { - s.bytes = bytes -} - -func (s *slideSshowResponse) Bytes() []byte { - return s.bytes -} - -func (s *slideSshowResponse) String() string { - return string(s.bytes) -} - func TestClient_Get(t *testing.T) { client, err := NewClient("test", "http://httpbin.org/") if err != nil { diff --git a/client/httplib/httplib.go b/client/httplib/httplib.go index f032a294..eb51f3a5 100644 --- a/client/httplib/httplib.go +++ b/client/httplib/httplib.go @@ -656,16 +656,11 @@ func (b *BeegoHTTPRequest) ToYAML(v interface{}) error { UnmarshalYAMLResponseToObjectFailed, "unmarshal yaml body to object failed.") } -// Response executes request client gets response manually. -func (b *BeegoHTTPRequest) Response() (*http.Response, error) { - return b.getResponse() -} - -// ResponseForValue attempts to resolve the response body to value using an existing method. +// ToValue attempts to resolve the response body to value using an existing method. // Calls Response inner. // If response header contain Content-Type, func will call ToJSON\ToXML\ToYAML. // Else it will try to parse body as json\yaml\xml, If all attempts fail, an error will be returned -func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error { +func (b *BeegoHTTPRequest) ToValue(value interface{}) error { if value == nil { return nil } @@ -674,8 +669,8 @@ func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error { if err != nil { return err } - contentType := strings.Split(resp.Header.Get(contentTypeKey), ";")[0] + contentType := strings.Split(resp.Header.Get(contentTypeKey), ";")[0] // try to parse it as content type switch contentType { case "application/json": @@ -697,8 +692,12 @@ func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error { return nil } - // TODO add new error type about can't parse body - return berror.Error(UnsupportedBodyType, "unsupported body data") + return berror.Error(UnmarshalResponseToObjectFailed, "unmarshal body to object failed.") +} + +// Response executes request client gets response manually. +func (b *BeegoHTTPRequest) Response() (*http.Response, error) { + return b.getResponse() } // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field.