-
Notifications
You must be signed in to change notification settings - Fork 191
/
Copy pathrespx.go
134 lines (111 loc) · 2.73 KB
/
respx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package httpreq
import (
"bytes"
"encoding/json"
"errors"
"io"
"net/http"
"github.com/gookit/goutil/netutil/httpctype"
)
// Resp alias of RespX
type Resp = RespX
// RespX wrap http.Response and add some useful methods.
type RespX struct {
*http.Response
// CostTime for a request-response
CostTime int64
}
// WrapResp wrap http.Response to RespX
func WrapResp(hr *http.Response, err error) (*RespX, error) {
if err != nil {
return nil, err
}
return &RespX{Response: hr}, nil
}
// NewResp instance
func NewResp(hr *http.Response) *RespX {
return &RespX{Response: hr}
}
// IsFail check
func (r *RespX) IsFail() bool {
return r.StatusCode != http.StatusOK
}
// IsOk check
func (r *RespX) IsOk() bool {
return r.StatusCode == http.StatusOK
}
// IsSuccessful check
func (r *RespX) IsSuccessful() bool {
return IsSuccessful(r.StatusCode)
}
// IsEmptyBody check response body is empty
func (r *RespX) IsEmptyBody() bool {
return r.ContentLength <= 0
}
// ContentType get response content type
func (r *RespX) ContentType() string {
return r.Header.Get(httpctype.Key)
}
// BodyString get body as string.
func (r *RespX) String() string {
return ResponseToString(r.Response)
}
// BodyString get body as string.
func (r *RespX) BodyString() string {
return r.BodyBuffer().String()
}
// BodyBuffer read body to buffer.
//
// NOTICE: must close resp body.
func (r *RespX) BodyBuffer() *bytes.Buffer {
buf := &bytes.Buffer{}
// prof: assign memory before read
if r.ContentLength > bytes.MinRead {
buf.Grow(int(r.ContentLength) + 2)
}
// NOTICE: must close resp body.
defer r.SafeCloseBody()
_, err := buf.ReadFrom(r.Body)
if err != nil {
panic(err)
}
return buf
}
// BindJSONOnOk body data on response status is 200.
// if ptr is nil, will discard body data.
//
// NOTICE: must close resp body.
func (r *RespX) BindJSONOnOk(ptr any) error {
// NOTICE: must close resp body.
defer r.SafeCloseBody()
if r.IsFail() {
_, _ = io.Copy(io.Discard, r.Body) // <-- add this line
return errors.New("response status is not equals to 200")
}
if ptr == nil {
_, _ = io.Copy(io.Discard, r.Body) // <-- add this line
return nil
}
return json.NewDecoder(r.Body).Decode(ptr)
}
// BindJSON body data to a ptr, will don't check status code.
// if ptr is nil, will discard body data.
//
// NOTICE: must close resp body.
func (r *RespX) BindJSON(ptr any) error {
// NOTICE: must close resp body.
defer r.SafeCloseBody()
if ptr == nil {
_, _ = io.Copy(io.Discard, r.Body) // <-- add this line
return nil
}
return json.NewDecoder(r.Body).Decode(ptr)
}
// CloseBody close resp body
func (r *RespX) CloseBody() error {
return r.Body.Close()
}
// SafeCloseBody close resp body, ignore error
func (r *RespX) SafeCloseBody() {
_ = r.Body.Close()
}