Simple HTTP and REST client library for Go
ps: 个人感觉resty比colly好用,不错先用的colly, 然后转到了resty
文档:https://pkg.go.dev/github.com/go-resty/resty/v2

Constants

  1. const (
  2. MethodGet = "GET"
  3. MethodPost = "POST"
  4. MethodPut = "PUT"
  5. MethodDelete = "DELETE"
  6. MethodPatch = "PATCH"
  7. MethodHead = "HEAD"
  8. MethodOptions = "OPTIONS"
  9. )

type Client

客户端结构用于创建带有客户端级别设置的Resty客户端,这些设置适用于客户端引发的所有请求
request的请求最后也是转到client去执行的

  1. type Client struct {
  2. HostURL string
  3. QueryParam url.Values
  4. FormData url.Values
  5. Header http.Header
  6. UserInfo *User
  7. Token string
  8. AuthScheme string
  9. Cookies []*http.Cookie
  10. Error reflect.Type
  11. Debug bool
  12. DisableWarn bool
  13. AllowGetMethodPayload bool
  14. RetryCount int
  15. RetryWaitTime time.Duration
  16. RetryMaxWaitTime time.Duration
  17. RetryConditions []RetryConditionFunc
  18. RetryAfter RetryAfterFunc
  19. JSONMarshal func(v interface{}) ([]byte, error)
  20. JSONUnmarshal func(data []byte, v interface{}) error
  21. // HeaderAuthorizationKey is used to set/access Request Authorization header
  22. // value when `SetAuthToken` option is used.
  23. HeaderAuthorizationKey string
  24. // contains filtered or unexported fields
  25. }

func New() *Client

  1. // Creating client1
  2. client1 := resty.New()
  3. resp1, err1 := client1.R().Get("http://httpbin.org/get")
  4. fmt.Println(resp1, err1)
  5. // Creating client2
  6. client2 := resty.New()
  7. resp2, err2 := client2.R().Get("http://httpbin.org/get")
  8. fmt.Println(resp2, err2)

func NewWithClient(hc http.Client) Client
func (c Client) AddRetryCondition(condition RetryConditionFunc) Client 增加重试策略
func (c Client) SetRetryAfter(callback RetryAfterFunc) Client
func (c Client) SetRetryCount(count int) Client 注意:这里的重试是针对client,req是依赖client发送的
func (c Client) SetRetryMaxWaitTime(maxWaitTime time.Duration) Client 默认2s
func (c Client) SetRetryWaitTime(waitTime time.Duration) Client 默认100ms
func (c Client) DisableTrace() Client 禁用追综
func (c Client) EnableTrace() Client 启用追综
func (c Client) GetClient() http.Client 获取一个client
func (c Client) IsProxySet() bool 是否设置了代理
func (c
Client) RemoveProxy() Client 移除代理
func (c
Client) SetProxy(proxyURL string) *Client

  1. client.SetProxy("http://proxyserver:8888")

func (c Client) NewRequest() Request 新建一个request
func (c Client) R() Request 新建一个request
func (c Client) OnAfterResponse(m ResponseMiddleware) Client

  1. client.OnAfterResponse(func(c *resty.Client, r *resty.Response) error {
  2. // Now you have access to Client and Response instance
  3. // manipulate it as per your need
  4. return nil // if its success otherwise return error
  5. })

func (c Client) SetPreRequestHook(h PreRequestHook) Client 在request前调用,只能设置一个
func (c Client) OnBeforeRequest(m RequestMiddleware) Client

  1. client.OnBeforeRequest(func(c *resty.Client, r *resty.Request) error {
  2. // Now you have access to Client and Request instance
  3. // manipulate it as per your need
  4. return nil // if its success otherwise return error
  5. })

func (c Client) OnError(h ErrorHook) Client
OnError方法添加了一个回调函数,该函数将在请求执行失败时运行。在尝试了所有重试(如果有的话)之后调用。如果有来自服务器的响应,错误将被包装在*ResponseError中,其中包含从服务器接收到的最后一个响应。

  1. client.OnError(func(req *resty.Request, err error) {
  2. if v, ok := err.(*resty.ResponseError); ok {
  3. // Do something with v.Response
  4. }
  5. // Log the error, increment a metric, etc...
  6. })

func (c Client) OnRequestLog(rl RequestLogCallback) Client
func (c Client) OnResponseLog(rl ResponseLogCallback) Client
func (c Client) SetAuthScheme(scheme string) Client 设置认证方案

  1. Authorization: <auth-scheme-value> <auth-token-value>
  2. For Example: To set the scheme to use OAuth
  3. client.SetAuthScheme("OAuth")

func (c Client) SetAuthToken(token string) Client

  1. Authorization: <auth-scheme> <auth-token-value>
  2. For Example: To set auth token BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F
  3. client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F

func (c Client) SetBasicAuth(username, password string) Client

  1. Authorization: Basic <base64-encoded-value>
  2. For Example: To set the header for username "go-resty" and password "welcome"
  3. client.SetBasicAuth("go-resty", "welcome")

func (c Client) SetCertificates(certs …tls.Certificate) Client

  1. // Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
  2. cert, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
  3. if err != nil {
  4. log.Fatalf("ERROR client certificate: %s", err)
  5. }
  6. // Create a resty client
  7. client := resty.New()
  8. client.SetCertificates(cert)

func (c Client) SetContentLength(l bool) Client 是否需要设置Content-Length
func (c Client) SetCookie(hc http.Cookie) *Client

  1. client.SetCookie(&http.Cookie{
  2. Name:"go-resty",
  3. Value:"This is cookie value",
  4. })

func (c Client) SetCookieJar(jar http.CookieJar) Client
func (c Client) SetDebug(d bool) Client 调试模式
func (c Client) SetDoNotParseResponse(parse bool) Client 不自动解析response

  • SetDoNotParseResponse方法指示’ Resty ‘不要自动解析响应体。Resty将原始响应体公开为’ io.ReadCloser ‘。也不要忘记关闭主体,否则可能会进入连接泄漏,没有连接重用。 注意:如果使用这个选项,响应中间件是不适用的。基本上,您已经从“Resty”接管了响应解析的控制权。

func (c Client) SetHeader(header, value string) Client
func (c Client) SetFormData(data map[string]string) Client
func (c Client) SetHeader(header, value string) Client
func (c Client) SetHeaders(headers map[string]string) Client
func (c Client) SetLogger(l Logger) Client
func (c Client) SetOutputDirectory(dirPath string) Client 设置下载的目录

  1. client.SetOutputDirectory("/save/http/response/here")

func (c Client) SetPathParam(param, value string) Client

  1. client.SetPathParam("userId", "sample@sample.com")
  2. Result:
  3. URL - /v1/users/{userId}/details
  4. Composed URL - /v1/users/sample@sample.com/details

func (c Client) SetPathParams(params map[string]string) Client

  1. client.SetPathParams(map[string]string{
  2. "userId": "sample@sample.com",
  3. "subAccountId": "100002",
  4. })
  5. Result:
  6. URL - /v1/users/{userId}/{subAccountId}/details
  7. Composed URL - /v1/users/sample@sample.com/100002/details

func (c Client) SetQueryParam(param, value string) Client

  1. client.
  2. SetQueryParam("search", "kitchen papers").
  3. SetQueryParam("size", "large")

func (c Client) SetQueryParams(params map[string]string) Client
func (c Client) SetRedirectPolicy(policies …interface{}) Client 设置重定向策略

  1. client.SetRedirectPolicy(FlexibleRedirectPolicy(20))
  2. // Need multiple redirect policies together
  3. client.SetRedirectPolicy(FlexibleRedirectPolicy(20), DomainCheckRedirectPolicy("host1.com", "host2.net"))

func (c Client) SetRootCertificate(pemFilePath string) Client
func (c Client) SetRootCertificateFromString(pemContent string) Client

  1. client.SetRootCertificate("/path/to/root/pemFile.pem")
  2. client.SetRootCertificateFromString("pem file content")

func (c Client) SetScheme(scheme string) Client
func (c Client) SetTLSClientConfig(config tls.Config) *Client

  1. / One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
  2. client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })
  3. // or One can disable security check (https)
  4. client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })

func (c Client) SetTimeout(timeout time.Duration) Client
func (c Client) SetTransport(transport http.RoundTripper) Client
SetTransport方法设置自定义’ http。传输’或任何’ http。在rest客户端中兼容RoundTripper的接口实现。 注意: —如果传输类型不是http。然后你可能无法利用一些rest客户端设置。 它覆盖Resty客户端传输实例及其配置。

  1. transport := &http.Transport{
  2. // somthing like Proxying to httptest.Server, etc...
  3. Proxy: func(req *http.Request) (*url.URL, error) {
  4. return url.Parse(server.URL)
  5. },
  6. }
  7. client.SetTransport(transport)

type ErrorHook

  1. type ErrorHook func(*Request, error)

type Option

  1. type Option func(*Options)
  2. func MaxWaitTime(value time.Duration) Option 设置请求之间休眠的最大等待时间
  3. func Retries(value int) Option
  4. func RetryConditions(conditions []RetryConditionFunc) Option
  5. func WaitTime(value time.Duration) Option

type Options

  1. type Options struct {
  2. // contains filtered or unexported fields
  3. }

type Logger

  1. type Logger interface {
  2. Errorf(format string, v ...interface{})
  3. Warnf(format string, v ...interface{})
  4. Debugf(format string, v ...interface{})
  5. }

type PreRequestHook

PreRequestHook类型用于请求钩子,在请求发送之前调用

  1. type PreRequestHook func(*Client, *http.Request) error

type RedirectPolicy

RedirectPolicy用于规范rest客户端的重定向。实现RedirectPolicy接口的对象可以注册为 Apply函数返回nil以继续重定向,否则返回error以停止重定向。

  1. type RedirectPolicy interface {
  2. Apply(req *http.Request, via []*http.Request) error
  3. }
  4. // 重定向只允许策略中提供的hostname
  5. func DomainCheckRedirectPolicy(hostnames ...string) RedirectPolicy
  6. resty.SetRedirectPolicy(DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
  7. // 重定向次数
  8. func FlexibleRedirectPolicy(noOfRedirect int) RedirectPolicy
  9. resty.SetRedirectPolicy(FlexibleRedirectPolicy(20))
  10. // 不允许重试
  11. func NoRedirectPolicy() RedirectPolicy
  12. resty.SetRedirectPolicy(NoRedirectPolicy())

type RedirectPolicyFunc

RedirectPolicyFunc类型是一个适配器,允许使用普通函数作为RedirectPolicy。如果f是一个具有适当签名的函数,则RedirectPolicyFunc(f)是一个调用f的RedirectPolicy对象。

  1. type RedirectPolicyFunc func(*http.Request, []*http.Request) error

func (f RedirectPolicyFunc) Apply(req http.Request, via []http.Request) error calls f(req, via)

type Request

  1. type Request struct {
  2. URL string
  3. Method string
  4. Token string
  5. AuthScheme string
  6. QueryParam url.Values
  7. FormData url.Values
  8. Header http.Header
  9. Time time.Time
  10. Body interface{}
  11. Result interface{}
  12. Error interface{}
  13. RawRequest *http.Request
  14. SRV *SRVRecord
  15. UserInfo *User
  16. Cookies []*http.Cookie
  17. // Attempt is to represent the request attempt made during a Resty
  18. // request execution flow, including retry count.
  19. //
  20. // Since v2.4.0
  21. Attempt int
  22. // contains filtered or unexported fields
  23. }

func (r Request) Context() context.Context 如果有就返回,没有使用context.Background()新建
func (r
Request) Delete(url string) (Response, error)
func (r
Request) EnableTrace() Request
func (r
Request) Execute(method, url string) (Response, error)
func (r
Request) Get(url string) (Response, error)
func (r
Request) Head(url string) (Response, error)
func (r
Request) Options(url string) (Response, error)
func (r
Request) Patch(url string) (Response, error)
func (r
Request) Post(url string) (Response, error)
func (r
Request) Put(url string) (Response, error)
func (r
Request) Send() (Response, error)
func (r
Request) SetAuthScheme(scheme string) Request 同client用法
func (r
Request) SetAuthToken(token string) Request 同client用法
func (r
Request) SetBasicAuth(username, password string) Request 同client用法
func (r
Request) SetBody(body interface{}) Request
func (r
Request) SetContentLength(l bool) Request
func (r
Request) SetContext(ctx context.Context) Request
func (r
Request) SetCookie(hc http.Cookie) Request
func (r Request) SetCookies(rs []http.Cookie) Request
func (r
Request) SetDoNotParseResponse(parse bool) Request
func (r
Request) SetFile(param, filePath string) *Request

  1. client.R().
  2. SetFile("my_file", "/Users/jeeva/Gas Bill - Sep.pdf")

func (r Request) SetFileReader(param, fileName string, reader io.Reader) Request

  1. client.R().
  2. SetFileReader("profile_img", "my-profile-img.png", bytes.NewReader(profileImgBytes)).
  3. SetFileReader("notes", "user-notes.txt", bytes.NewReader(notesBytes))

func (r Request) SetFiles(files map[string]string) Request

  1. client.R().
  2. SetFiles(map[string]string{
  3. "my_file1": "/Users/jeeva/Gas Bill - Sep.pdf",
  4. "my_file2": "/Users/jeeva/Electricity Bill - Sep.pdf",
  5. "my_file3": "/Users/jeeva/Water Bill - Sep.pdf",
  6. })

func (r Request) SetFormData(data map[string]string) Request

  1. // 自动将请求头content type 设置为 `application/x-www-form-urlencoded`
  2. client.R().
  3. SetFormData(map[string]string{
  4. "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
  5. "user_id": "3455454545",
  6. })

func (r Request) SetHeader(header, value string) Request
func (r Request) SetHeaders(headers map[string]string) Request

  1. client.R().
  2. SetHeaders(map[string]string{
  3. "Content-Type": "application/json",
  4. "Accept": "application/json",
  5. })

func (r Request) SetMultipartField(param, fileName, contentType string, reader io.Reader) Request
func (r Request) SetMultipartFields(fields …MultipartField) *Request

  1. client.R().SetMultipartFields(
  2. &resty.MultipartField{
  3. Param: "uploadManifest1",
  4. FileName: "upload-file-1.json",
  5. ContentType: "application/json",
  6. Reader: strings.NewReader(`{"input": {"name": "Uploaded document 1", "_filename" : ["file1.txt"]}}`),
  7. },
  8. &resty.MultipartField{
  9. Param: "uploadManifest2",
  10. FileName: "upload-file-2.json",
  11. ContentType: "application/json",
  12. Reader: strings.NewReader(`{"input": {"name": "Uploaded document 2", "_filename" : ["file2.txt"]}}`),
  13. })

func (r Request) SetMultipartFormData(data map[string]string) Request
func (r Request) SetOutput(file string) Request 指定下载文件的绝对路径或相对路径(做目录使用)

  1. client.R().
  2. SetOutput("/Users/jeeva/Downloads/ReplyWithHeader-v5.1-beta.zip").
  3. Get("http://bit.ly/1LouEKr")

func (r Request) SetPathParam(param, value string) Request
func (r Request) SetPathParams(params map[string]string) Request

  1. client.R().SetPathParams(map[string]string{
  2. "userId": "sample@sample.com",
  3. "subAccountId": "100002",
  4. })
  5. Result:
  6. URL - /v1/users/{userId}/{subAccountId}/details
  7. Composed URL - /v1/users/sample@sample.com/100002/details

func (r Request) SetQueryParam(param, value string) Request
func (r Request) SetQueryParams(params map[string]string) Request
func (r Request) SetQueryParamsFromValues(params url.Values) Request

  1. For Example: `status=pending&status=approved&status=open` in the URL after `?`
  2. client.R().
  3. SetQueryParamsFromValues(url.Values{
  4. "status": []string{"pending", "approved", "open"},
  5. })

func (r Request) SetQueryString(query string) Request
func (r *Request) TraceInfo() TraceInfo

type RequestLog

RequestLog结构用于从rest请求实例收集用于调试日志的信息。它在rest实际记录信息之前被发送到请求日志回调

  1. type RequestLog struct {
  2. Header http.Header
  3. Body string
  4. }

type RequestLogCallback

RequestLogCallback type用于请求日志,在记录请求之前调用

  1. type RequestLogCallback func(*RequestLog) error

type RequestMiddleware

RequestMiddleware类型用于请求中间件,在请求发送之前调用

  1. type RequestMiddleware func(*Client, *Request) error

type Response

响应结构保存已执行请求的响应值

  1. type Response struct {
  2. Request *Request
  3. RawResponse *http.Response
  4. // contains filtered or unexported fields
  5. }

func (r Response) Body() []byte 如果使用了 Request.SetOutput ,它将是ni
func (r
Response) Cookies() []http.Cookie
func (r
Response) Error() interface{} 如果Error方法有一个Error对象,则返回该对象
func (r Response) Header() http.Header
func (r
Response) IsError() bool 如果HTTP状态’ code >= 400 ‘,则IsError方法返回true,否则返回false
func (r Response) IsSuccess() bool 如果HTTP状态’ code >= 200 and <= 299 ‘否则返回true
func (r
Response) Proto() string
func (r *Response) RawBody() io.ReadCloser

  • RawBody方法公开HTTP原始响应体。使用这个方法结合’ SetDoNotParseResponse ‘选项,否则你会得到一个错误为’ read err: http: read on closed response body ‘。 不要忘记关闭阀体,否则可能会进入连接泄漏,没有连接重用。基本上,您已经从“Resty”接管了响应解析的控制权。

func (r Response) ReceivedAt() time.Time
func (r
Response) Size() int64
func (r Response) Status() string Example: 200 OK
func (r
Response) StatusCode() int Example: 200
func (r Response) String() string 以字符串的方式返回请求的响应
func (r
Response) Time() time.Duration 请求的耗时

type ResponseError

  1. type ResponseError struct {
  2. Response *Response
  3. Err error
  4. }

func (e ResponseError) Error() string
func (e
ResponseError) Unwrap() error

type ResponseLog

ResponseLog结构用于从rest响应实例收集调试日志信息。它在rest实际记录信息之前被发送到响应日志回调

  1. type ResponseLog struct {
  2. Header http.Header
  3. Body string
  4. }

type ResponseLogCallback

ResponseLogCallback类型用于响应日志,在记录响应之前调用

  1. type ResponseLogCallback func(*ResponseLog) error

type ResponseMiddleware

ResponseMiddleware类型用于响应中间件,在收到响应后调用

  1. type ResponseMiddleware func(*Client, *Response) error

type RetryAfterFunc

返回重试之前等待的时间,error不为nil,则终止重试

  1. type RetryAfterFunc func(*Client, *Response) (time.Duration, error)

type RetryConditionFunc

控制重试

  1. type RetryConditionFunc func(*Response, error) bool

type TraceInfo

  1. type TraceInfo struct {
  2. // DNSLookup is a duration that transport took to perform
  3. // DNS lookup.
  4. DNSLookup time.Duration
  5. // ConnTime is a duration that took to obtain a successful connection.
  6. ConnTime time.Duration
  7. // TCPConnTime is a duration that took to obtain the TCP connection.
  8. TCPConnTime time.Duration
  9. // TLSHandshake is a duration that TLS handshake took place.
  10. TLSHandshake time.Duration
  11. // ServerTime is a duration that server took to respond first byte.
  12. ServerTime time.Duration
  13. // ResponseTime is a duration since first response byte from server to
  14. // request completion.
  15. ResponseTime time.Duration
  16. // TotalTime is a duration that total request took end-to-end.
  17. TotalTime time.Duration
  18. // IsConnReused is whether this connection has been previously
  19. // used for another HTTP request.
  20. IsConnReused bool
  21. // IsConnWasIdle is whether this connection was obtained from an
  22. // idle pool.
  23. IsConnWasIdle bool
  24. // ConnIdleTime is a duration how long the connection was previously
  25. // idle, if IsConnWasIdle is true.
  26. ConnIdleTime time.Duration
  27. // RequestAttempt is to represent the request attempt made during a Resty
  28. // request execution flow, including retry count.
  29. RequestAttempt int
  30. // RemoteAddr returns the remote network address.
  31. RemoteAddr net.Addr
  32. }

type User

  1. type User struct {
  2. Username, Password string
  3. }

小技巧

看源码中怎么关闭rsp.body的

  1. defer closeq(rsp.body)
  2. func closeq(v interface{}) {
  3. if c, ok := v.(io.Closer); ok {
  4. silently(c.Close())
  5. }
  6. }
  7. func silently(_ ...interface{}) {}

一般的,我们是这么关闭的

  1. defer rsp.body.Close()
  2. 这样写是不规范的,过不了代码检测,因为还没处理err
  3. 于是可以这样
  4. defer func(){
  5. _ = rsp.body.Close()
  6. }()
  7. 很明显 代码到处这样写很丑