add httpclient add options
This commit is contained in:
parent
29849ddb36
commit
575bf62fd3
@ -1,33 +0,0 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ClientOption func(client *Client) error
|
||||
|
||||
// client设置
|
||||
func WithTimeout(connectTimeout, readWriteTimeout time.Duration) ClientOption
|
||||
func WithEnableCookie(enable bool) ClientOption
|
||||
func WithUserAgent(userAgent string) ClientOption
|
||||
func WithCookie(cookie *http.Cookie) ClientOption
|
||||
func WithTransport(transport http.RoundTripper) ClientOption
|
||||
func WithProxy(proxy func(*http.Request) (*url.URL, error)) ClientOption
|
||||
func WithCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) ClientOption
|
||||
func WithAccept(accept string) ClientOption
|
||||
@ -1,25 +0,0 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
|
||||
import "github.com/beego/beego/v2/client/httplib"
|
||||
|
||||
type BeegoHttpRequestOption func(request *httplib.BeegoHTTPRequest) error
|
||||
|
||||
// Req设置
|
||||
func WithTokenFactory(tokenFactory func() (string, error)) BeegoHttpRequestOption
|
||||
func WithBasicAuth(basicAuth func() (string, error)) BeegoHttpRequestOption
|
||||
func WithFilters(fcs ...httplib.FilterChain) BeegoHttpRequestOption
|
||||
func WithContentType(contentType string) BeegoHttpRequestOption
|
||||
175
client/httplib/client_option.go
Normal file
175
client/httplib/client_option.go
Normal file
@ -0,0 +1,175 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ClientOption func(client *Client) error
|
||||
type BeegoHttpRequestOption func(request *BeegoHTTPRequest) error
|
||||
|
||||
// WithEnableCookie will enable cookie in all subsequent request
|
||||
func WithEnableCookie(enable bool) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.EnableCookie = enable
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableCookie will adds UA in all subsequent request
|
||||
func WithUserAgent(userAgent string) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.UserAgent = userAgent
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTLSClientConfig will adds tls config in all subsequent request
|
||||
func WithTLSClientConfig(config *tls.Config) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.TLSClientConfig = config
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithTransport will set transport field in all subsequent request
|
||||
func WithTransport(transport http.RoundTripper) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.Transport = transport
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithProxy will set http proxy field in all subsequent request
|
||||
func WithProxy(proxy func(*http.Request) (*url.URL, error)) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.Proxy = proxy
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithCheckRedirect will specifies the policy for handling redirects in all subsequent request
|
||||
func WithCheckRedirect(redirect func(req *http.Request, via []*http.Request) error) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.CheckRedirect = redirect
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHTTPSetting can replace beegoHTTPSeting
|
||||
func WithHTTPSetting(setting BeegoHTTPSettings) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting = &setting
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithEnableGzip will enable gzip in all subsequent request
|
||||
func WithEnableGzip(enable bool) ClientOption {
|
||||
return func(client *Client) error {
|
||||
client.Setting.Gzip = enable
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// BeegoHttpRequestOption
|
||||
|
||||
// WithTimeout sets connect time out and read-write time out for BeegoRequest.
|
||||
func WithTimeout(connectTimeout, readWriteTimeout time.Duration) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.SetTimeout(connectTimeout, readWriteTimeout)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithHeader adds header item string in request.
|
||||
func WithHeader(key, value string) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.Header(key, value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithCookie adds a cookie to the request.
|
||||
func WithCookie(cookie *http.Cookie) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.Header("Cookie", cookie.String())
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Withtokenfactory adds a custom function to set Authorization
|
||||
func WithTokenFactory(tokenFactory func() (string, error)) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
t, err := tokenFactory()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.Header("Authorization", t)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBasicAuth adds a custom function to set basic auth
|
||||
func WithBasicAuth(basicAuth func() (string, string, error)) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
username, password, err := basicAuth()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SetBasicAuth(username, password)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithFilters will use the filter as the invocation filters
|
||||
func WithFilters(fcs ...FilterChain) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.SetFilters(fcs...)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithContentType adds ContentType in header
|
||||
func WithContentType(contentType string) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.Header("Content-Type", contentType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithParam adds query param in to request.
|
||||
func WithParam(key, value string) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.Param(key, value)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithRetry set retry times and delay for the request
|
||||
// default is 0 (never retry)
|
||||
// -1 retry indefinitely (forever)
|
||||
// Other numbers specify the exact retry amount
|
||||
func WithRetry(times int, delay time.Duration) BeegoHttpRequestOption {
|
||||
return func(request *BeegoHTTPRequest) error {
|
||||
request.Retries(times)
|
||||
request.RetryDelay(delay)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
250
client/httplib/client_option_test.go
Normal file
250
client/httplib/client_option_test.go
Normal file
@ -0,0 +1,250 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestOption_WithEnableCookie(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/",
|
||||
WithEnableCookie(true))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
v := "smallfish"
|
||||
var str *string
|
||||
err = client.Get(&str, "/cookies/set?k1="+v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(*str)
|
||||
|
||||
err = client.Get(&str, "/cookies")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in cookie")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithUserAgent(t *testing.T) {
|
||||
v := "beego"
|
||||
client, err := NewClient("test", "http://httpbin.org/",
|
||||
WithUserAgent(v))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var str *string
|
||||
err = client.Get(&str, "/headers")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in user-agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithCheckRedirect(t *testing.T) {
|
||||
client, err := NewClient("test", "https://goolnk.com/33BD2j",
|
||||
WithCheckRedirect(func(redirectReq *http.Request, redirectVia []*http.Request) error {
|
||||
return errors.New("Redirect triggered")
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = client.Get(nil, "")
|
||||
assert.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestOption_WithHTTPSetting(t *testing.T) {
|
||||
v := "beego"
|
||||
var setting BeegoHTTPSettings
|
||||
setting.EnableCookie = true
|
||||
setting.UserAgent = v
|
||||
setting.Transport = &http.Transport{
|
||||
DialContext: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
DualStack: true,
|
||||
}).DialContext,
|
||||
MaxIdleConns: 50,
|
||||
IdleConnTimeout: 90 * time.Second,
|
||||
ExpectContinueTimeout: 1 * time.Second,
|
||||
}
|
||||
setting.ReadWriteTimeout = 5 * time.Second
|
||||
|
||||
client, err := NewClient("test", "http://httpbin.org/",
|
||||
WithHTTPSetting(setting))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var str *string
|
||||
err = client.Get(&str, "/get")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in user-agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithHeader(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client.CommonOpts = append(client.CommonOpts, WithHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36"))
|
||||
|
||||
var str *string
|
||||
err = client.Get(&str, "/headers")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, "Mozilla/5.0")
|
||||
if n == -1 {
|
||||
t.Fatal("Mozilla/5.0 not found in user-agent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithTokenFactory(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client.CommonOpts = append(client.CommonOpts,
|
||||
WithTokenFactory(func() (string, error) {
|
||||
return "testauth", nil
|
||||
}))
|
||||
|
||||
var str *string
|
||||
err = client.Get(&str, "/headers")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, "testauth")
|
||||
if n == -1 {
|
||||
t.Fatal("Auth is not set in request")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithBasicAuth(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var str *string
|
||||
err = client.Get(&str, "/basic-auth/user/passwd",
|
||||
WithBasicAuth(func() (string, string, error) {
|
||||
return "user", "passwd", nil
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
n := strings.Index(*str, "authenticated")
|
||||
if n == -1 {
|
||||
t.Fatal("authenticated not found in response")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithContentType(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
v := "application/json"
|
||||
var str *string
|
||||
err = client.Get(&str, "/headers", WithContentType(v))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithParam(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
v := "smallfish"
|
||||
var str *string
|
||||
err = client.Get(&str, "/get", WithParam("username", v))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Log(str)
|
||||
|
||||
n := strings.Index(*str, v)
|
||||
if n == -1 {
|
||||
t.Fatal(v + " not found in header")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOption_WithRetry(t *testing.T) {
|
||||
client, err := NewClient("test", "https://goolnk.com/33BD2j",
|
||||
WithCheckRedirect(func(redirectReq *http.Request, redirectVia []*http.Request) error {
|
||||
return errors.New("Redirect triggered")
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
retryAmount := 1
|
||||
retryDelay := 1400 * time.Millisecond
|
||||
startTime := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
|
||||
err = client.Get(nil, "", WithRetry(retryAmount, retryDelay))
|
||||
|
||||
assert.NotNil(t, err)
|
||||
endTime := time.Now().UnixNano() / int64(time.Millisecond)
|
||||
elapsedTime := endTime - startTime
|
||||
delayedTime := int64(retryAmount) * retryDelay.Milliseconds()
|
||||
if elapsedTime < delayedTime {
|
||||
t.Errorf("Not enough retries. Took %dms. Delay was meant to take %dms", elapsedTime, delayedTime)
|
||||
}
|
||||
}
|
||||
@ -12,26 +12,26 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package client
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/v2/client/httplib"
|
||||
"github.com/beego/beego/v2/core/berror"
|
||||
)
|
||||
|
||||
// Client provides an HTTP client supporting chain call
|
||||
type Client struct {
|
||||
Name string
|
||||
Endpoint string
|
||||
CommonOpts []BeegoHttpRequestOption
|
||||
|
||||
Setting *httplib.BeegoHTTPSettings
|
||||
pointer *ResponsePointer
|
||||
Setting *BeegoHTTPSettings
|
||||
pointer *responsePointer
|
||||
}
|
||||
|
||||
type ResponsePointer struct {
|
||||
type responsePointer struct {
|
||||
response **http.Response
|
||||
statusCode **int
|
||||
header **http.Header
|
||||
@ -39,12 +39,14 @@ type ResponsePointer struct {
|
||||
contentLength **int64
|
||||
}
|
||||
|
||||
// NewClient
|
||||
// NewClient return a new http client
|
||||
func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, error) {
|
||||
res := &Client{
|
||||
Name: name,
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
setting := GetDefaultSetting()
|
||||
res.Setting = &setting
|
||||
for _, o := range opts {
|
||||
err := o(res)
|
||||
if err != nil {
|
||||
@ -58,7 +60,7 @@ func NewClient(name string, endpoint string, opts ...ClientOption) (*Client, err
|
||||
func (c *Client) Response(resp **http.Response) *Client {
|
||||
if c.pointer == nil {
|
||||
newC := *c
|
||||
newC.pointer = &ResponsePointer{
|
||||
newC.pointer = &responsePointer{
|
||||
response: resp,
|
||||
}
|
||||
return &newC
|
||||
@ -71,7 +73,7 @@ func (c *Client) Response(resp **http.Response) *Client {
|
||||
func (c *Client) StatusCode(code **int) *Client {
|
||||
if c.pointer == nil {
|
||||
newC := *c
|
||||
newC.pointer = &ResponsePointer{
|
||||
newC.pointer = &responsePointer{
|
||||
statusCode: code,
|
||||
}
|
||||
return &newC
|
||||
@ -84,7 +86,7 @@ func (c *Client) StatusCode(code **int) *Client {
|
||||
func (c *Client) Headers(headers **http.Header) *Client {
|
||||
if c.pointer == nil {
|
||||
newC := *c
|
||||
newC.pointer = &ResponsePointer{
|
||||
newC.pointer = &responsePointer{
|
||||
header: headers,
|
||||
}
|
||||
return &newC
|
||||
@ -97,7 +99,7 @@ func (c *Client) Headers(headers **http.Header) *Client {
|
||||
func (c *Client) HeaderValue(key string, value **string) *Client {
|
||||
if c.pointer == nil {
|
||||
newC := *c
|
||||
newC.pointer = &ResponsePointer{
|
||||
newC.pointer = &responsePointer{
|
||||
headerValues: map[string]**string{
|
||||
key: value,
|
||||
},
|
||||
@ -120,7 +122,7 @@ func (c *Client) ContentType(contentType **string) *Client {
|
||||
func (c *Client) ContentLength(contentLength **int64) *Client {
|
||||
if c.pointer == nil {
|
||||
newC := *c
|
||||
newC.pointer = &ResponsePointer{
|
||||
newC.pointer = &responsePointer{
|
||||
contentLength: contentLength,
|
||||
}
|
||||
return &newC
|
||||
@ -155,19 +157,19 @@ func (c *Client) setPointers(resp *http.Response) {
|
||||
}
|
||||
|
||||
// initRequest will apply all the client setting, common option and request option
|
||||
func (c *Client) newRequest(method, path string, opts []BeegoHttpRequestOption) (*httplib.BeegoHTTPRequest, error) {
|
||||
var req *httplib.BeegoHTTPRequest
|
||||
func (c *Client) newRequest(method, path string, opts []BeegoHttpRequestOption) (*BeegoHTTPRequest, error) {
|
||||
var req *BeegoHTTPRequest
|
||||
switch method {
|
||||
case http.MethodGet:
|
||||
req = httplib.Get(c.Endpoint + path)
|
||||
req = Get(c.Endpoint + path)
|
||||
case http.MethodPost:
|
||||
req = httplib.Post(c.Endpoint + path)
|
||||
req = Post(c.Endpoint + path)
|
||||
case http.MethodPut:
|
||||
req = httplib.Put(c.Endpoint + path)
|
||||
req = Put(c.Endpoint + path)
|
||||
case http.MethodDelete:
|
||||
req = httplib.Delete(c.Endpoint + path)
|
||||
req = Delete(c.Endpoint + path)
|
||||
case http.MethodHead:
|
||||
req = httplib.Head(c.Endpoint + path)
|
||||
req = Head(c.Endpoint + path)
|
||||
}
|
||||
|
||||
req = req.Setting(*c.Setting)
|
||||
@ -187,7 +189,7 @@ func (c *Client) newRequest(method, path string, opts []BeegoHttpRequestOption)
|
||||
}
|
||||
|
||||
// handleResponse try to parse body to meaningful value
|
||||
func (c *Client) handleResponse(value interface{}, req *httplib.BeegoHTTPRequest) error {
|
||||
func (c *Client) handleResponse(value interface{}, req *BeegoHTTPRequest) error {
|
||||
// send request
|
||||
resp, err := req.Response()
|
||||
if err != nil {
|
||||
@ -195,6 +197,10 @@ func (c *Client) handleResponse(value interface{}, req *httplib.BeegoHTTPRequest
|
||||
}
|
||||
c.setPointers(resp)
|
||||
|
||||
if value == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// handle basic type
|
||||
switch v := value.(type) {
|
||||
case **string:
|
||||
@ -217,7 +223,7 @@ func (c *Client) handleResponse(value interface{}, req *httplib.BeegoHTTPRequest
|
||||
switch strings.Split(resp.Header.Get("Content-Type"), ";")[0] {
|
||||
case "application/json":
|
||||
return req.ToJSON(value)
|
||||
case "text/xml":
|
||||
case "text/xml", "application/xml":
|
||||
return req.ToXML(value)
|
||||
case "text/yaml", "application/x-yaml":
|
||||
return req.ToYAML(value)
|
||||
@ -235,7 +241,7 @@ func (c *Client) handleResponse(value interface{}, req *httplib.BeegoHTTPRequest
|
||||
}
|
||||
|
||||
// TODO add new error type about can't parse body
|
||||
return berror.Error(httplib.UnsupportedBodyType, "unsupported body data")
|
||||
return berror.Error(UnsupportedBodyType, "unsupported body data")
|
||||
}
|
||||
|
||||
// Get Send a GET request and try to give its result value
|
||||
258
client/httplib/httpclient_test.go
Normal file
258
client/httplib/httpclient_test.go
Normal file
@ -0,0 +1,258 @@
|
||||
// Copyright 2020 beego
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package httplib
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
client, err := NewClient("test1", "http://beego.me", WithEnableCookie(true))
|
||||
assert.NoError(t, err)
|
||||
assert.NotNil(t, client)
|
||||
assert.Equal(t, true, client.Setting.EnableCookie)
|
||||
}
|
||||
|
||||
func TestClient_Response(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
err = client.Response(&resp).Get(nil, "status/203")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 203, resp.StatusCode)
|
||||
}
|
||||
|
||||
func TestClient_StatusCode(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var statusCode *int
|
||||
err = client.StatusCode(&statusCode).Get(nil, "status/203")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, 203, *statusCode)
|
||||
}
|
||||
|
||||
func TestClient_Headers(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var header *http.Header
|
||||
err = client.Headers(&header).Get(nil, "bytes/123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "123", header.Get("Content-Length"))
|
||||
}
|
||||
|
||||
func TestClient_HeaderValue(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var val *string
|
||||
err = client.Headers(nil).HeaderValue("Content-Length", &val).Get(nil, "bytes/123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "123", *val)
|
||||
}
|
||||
|
||||
func TestClient_ContentType(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var contentType *string
|
||||
err = client.ContentType(&contentType).Get(nil, "bytes/123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "application/octet-stream", *contentType)
|
||||
}
|
||||
|
||||
func TestClient_ContentLength(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var contentLength *int64
|
||||
err = client.ContentLength(&contentLength).Get(nil, "bytes/123")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, int64(123), *contentLength)
|
||||
}
|
||||
|
||||
type total struct {
|
||||
Slideshow slideshow `json:"slideshow" yaml:"slideshow"`
|
||||
}
|
||||
|
||||
type slideshow struct {
|
||||
XMLName xml.Name `xml:"slideshow"`
|
||||
|
||||
Title string `json:"title" yaml:"title" xml:"title,attr"`
|
||||
Author string `json:"author" yaml:"author" xml:"author,attr"`
|
||||
Date string `json:"date" yaml:"date" xml:"date,attr"`
|
||||
Slides []slide `json:"slides" yaml:"slides" xml:"slide"`
|
||||
}
|
||||
|
||||
type slide struct {
|
||||
XMLName xml.Name `xml:"slide"`
|
||||
|
||||
Title string `json:"title" yaml:"title" xml:"title"`
|
||||
}
|
||||
|
||||
func TestClient_Get(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org/")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// basic type
|
||||
var s *string
|
||||
err = client.Get(&s, "/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "HTTPBIN is awesome", *s)
|
||||
|
||||
var bytes *[]byte
|
||||
err = client.Get(&bytes, "/base64/SFRUUEJJTiBpcyBhd2Vzb21l")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, []byte("HTTPBIN is awesome"), *bytes)
|
||||
|
||||
// json
|
||||
var tp *total
|
||||
err = client.Get(&tp, "/json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "Sample Slide Show", tp.Slideshow.Title)
|
||||
assert.Equal(t, 2, len(tp.Slideshow.Slides))
|
||||
assert.Equal(t, "Overview", tp.Slideshow.Slides[1].Title)
|
||||
|
||||
// xml
|
||||
var ssp *slideshow
|
||||
err = client.Get(&ssp, "/base64/PD94bWwgPz48c2xpZGVzaG93CnRpdGxlPSJTYW1wbGUgU2xpZGUgU2hvdyIKZGF0ZT0iRGF0ZSBvZiBwdWJsaWNhdGlvbiIKYXV0aG9yPSJZb3VycyBUcnVseSI+PHNsaWRlIHR5cGU9ImFsbCI+PHRpdGxlPldha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyE8L3RpdGxlPjwvc2xpZGU+PHNsaWRlIHR5cGU9ImFsbCI+PHRpdGxlPk92ZXJ2aWV3PC90aXRsZT48aXRlbT5XaHkgPGVtPldvbmRlcldpZGdldHM8L2VtPiBhcmUgZ3JlYXQ8L2l0ZW0+PGl0ZW0vPjxpdGVtPldobyA8ZW0+YnV5czwvZW0+IFdvbmRlcldpZGdldHM8L2l0ZW0+PC9zbGlkZT48L3NsaWRlc2hvdz4=")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "Sample Slide Show", ssp.Title)
|
||||
assert.Equal(t, 2, len(ssp.Slides))
|
||||
assert.Equal(t, "Overview", ssp.Slides[1].Title)
|
||||
|
||||
// yaml
|
||||
tp = nil
|
||||
err = client.Get(&tp, "/base64/c2xpZGVzaG93OgogIGF1dGhvcjogWW91cnMgVHJ1bHkKICBkYXRlOiBkYXRlIG9mIHB1YmxpY2F0aW9uCiAgc2xpZGVzOgogIC0gdGl0bGU6IFdha2UgdXAgdG8gV29uZGVyV2lkZ2V0cyEKICAgIHR5cGU6IGFsbAogIC0gaXRlbXM6CiAgICAtIFdoeSA8ZW0+V29uZGVyV2lkZ2V0czwvZW0+IGFyZSBncmVhdAogICAgLSBXaG8gPGVtPmJ1eXM8L2VtPiBXb25kZXJXaWRnZXRzCiAgICB0aXRsZTogT3ZlcnZpZXcKICAgIHR5cGU6IGFsbAogIHRpdGxlOiBTYW1wbGUgU2xpZGUgU2hvdw==")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.Equal(t, "Sample Slide Show", tp.Slideshow.Title)
|
||||
assert.Equal(t, 2, len(tp.Slideshow.Slides))
|
||||
assert.Equal(t, "Overview", tp.Slideshow.Slides[1].Title)
|
||||
|
||||
}
|
||||
|
||||
func TestClient_Post(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var s *string
|
||||
err = client.Get(&s, "/json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
err = client.Response(&resp).Post(&s, "/post", *s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotNil(t, resp)
|
||||
assert.Equal(t, http.MethodPost, resp.Request.Method)
|
||||
}
|
||||
|
||||
func TestClient_Put(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var s *string
|
||||
err = client.Get(&s, "/json")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
err = client.Response(&resp).Put(&s, "/put", *s)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotNil(t, resp)
|
||||
assert.Equal(t, http.MethodPut, resp.Request.Method)
|
||||
}
|
||||
|
||||
func TestClient_Delete(t *testing.T) {
|
||||
client, err := NewClient("test", "http://httpbin.org")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
err = client.Response(&resp).Delete(nil, "/delete")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotNil(t, resp)
|
||||
assert.Equal(t, http.MethodDelete, resp.Request.Method)
|
||||
}
|
||||
|
||||
func TestClient_Head(t *testing.T) {
|
||||
client, err := NewClient("test", "http://beego.me")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var resp *http.Response
|
||||
err = client.Response(&resp).Head(nil, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
assert.NotNil(t, resp)
|
||||
assert.Equal(t, http.MethodHead, resp.Request.Method)
|
||||
}
|
||||
@ -39,7 +39,7 @@ func TestResponse(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestDoRequest(t *testing.T) {
|
||||
req := Get("https://goolnk.com/33BD2j")
|
||||
req := Get("https://goolnk.com/")
|
||||
retryAmount := 1
|
||||
req.Retries(1)
|
||||
req.RetryDelay(1400 * time.Millisecond)
|
||||
|
||||
@ -55,6 +55,11 @@ func SetDefaultSetting(setting BeegoHTTPSettings) {
|
||||
defaultSetting = setting
|
||||
}
|
||||
|
||||
// SetDefaultSetting return current default setting
|
||||
func GetDefaultSetting() BeegoHTTPSettings {
|
||||
return defaultSetting
|
||||
}
|
||||
|
||||
var defaultSetting = BeegoHTTPSettings{
|
||||
UserAgent: "beegoServer",
|
||||
ConnectTimeout: 60 * time.Second,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user