This commit is contained in:
holooooo 2021-05-21 16:56:52 +08:00
parent 9b418271cc
commit b0d6f3bd2f
5 changed files with 75 additions and 45 deletions

View File

@ -34,18 +34,6 @@ func (r *respCarrier) SetHttpResponse(resp *http.Response) {
r.Resp = resp 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) { func TestOption_WithEnableCookie(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/", client, err := NewClient("test", "http://httpbin.org/",
WithEnableCookie(true)) WithEnableCookie(true))

View File

@ -124,3 +124,11 @@ Make sure that:
1. You pass valid structure pointer to the function; 1. You pass valid structure pointer to the function;
2. The body is valid YAML document 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
`)

View File

@ -15,6 +15,9 @@
package httplib package httplib
import ( import (
"bytes"
"io"
"io/ioutil"
"net/http" "net/http"
) )
@ -27,17 +30,32 @@ type Client struct {
Setting BeegoHTTPSettings 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 { type HttpResponseCarrier interface {
SetHttpResponse(resp *http.Response) SetHttpResponse(resp *http.Response)
} }
// If value implement this interface. bytes of http.response will saved by SetHttpResponse // HttpBodyCarrier If value implement HttpBodyCarrier. http.Response.Body will pass to SetReader
type ResponseBytesCarrier interface { type HttpBodyCarrier interface {
// Cause of when user get http.response, the body stream is closed. So need to pass bytes by 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) 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 // NewClient return a new http client
func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, error) { func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, error) {
res := &Client{ res := &Client{
@ -67,18 +85,47 @@ func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error
if err != nil { if err != nil {
return err return err
} }
if carrier, ok := (value).(HttpResponseCarrier); ok {
(carrier).SetHttpResponse(resp) switch carrier := value.(type) {
} case HttpResponseCarrier:
if carrier, ok := (value).(ResponseBytesCarrier); ok { b, err := req.Bytes()
bytes, err := req.Bytes()
if err != nil { if err != nil {
return err 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 // Get Send a GET request and try to give its result value

View File

@ -55,18 +55,6 @@ func (s *slideSshowResponse) SetHttpResponse(resp *http.Response) {
s.Resp = resp 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) { func TestClient_Get(t *testing.T) {
client, err := NewClient("test", "http://httpbin.org/") client, err := NewClient("test", "http://httpbin.org/")
if err != nil { if err != nil {

View File

@ -656,16 +656,11 @@ func (b *BeegoHTTPRequest) ToYAML(v interface{}) error {
UnmarshalYAMLResponseToObjectFailed, "unmarshal yaml body to object failed.") UnmarshalYAMLResponseToObjectFailed, "unmarshal yaml body to object failed.")
} }
// Response executes request client gets response manually. // ToValue attempts to resolve the response body to value using an existing method.
func (b *BeegoHTTPRequest) Response() (*http.Response, error) {
return b.getResponse()
}
// ResponseForValue attempts to resolve the response body to value using an existing method.
// Calls Response inner. // Calls Response inner.
// If response header contain Content-Type, func will call ToJSON\ToXML\ToYAML. // 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 // 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 { if value == nil {
return nil return nil
} }
@ -674,8 +669,8 @@ func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error {
if err != nil { if err != nil {
return err 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 // try to parse it as content type
switch contentType { switch contentType {
case "application/json": case "application/json":
@ -697,8 +692,12 @@ func (b *BeegoHTTPRequest) ResponseForValue(value interface{}) error {
return nil return nil
} }
// TODO add new error type about can't parse body return berror.Error(UnmarshalResponseToObjectFailed, "unmarshal body to object failed.")
return berror.Error(UnsupportedBodyType, "unsupported body data") }
// 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. // TimeoutDialer returns functions of connection dialer with timeout settings for http.Transport Dial field.