-
Notifications
You must be signed in to change notification settings - Fork 0
/
response.go
132 lines (107 loc) · 2.52 KB
/
response.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
package rest
import (
"fmt"
"io"
"net/http"
"strings"
"sync"
"github.com/yoas0bi/micro-toolkit/client/compressor"
"github.com/yoas0bi/micro-toolkit/client/negotiator"
"github.com/yoas0bi/micro-toolkit/logger"
)
func NewResponse(c *RESTClient) *Response {
return &Response{
log: c.log.Named("response"),
}
}
// Response contains the result of calling Request.Do().
type Response struct {
body io.ReadCloser
headers http.Header
statusCode int
err error
bf []byte
isRead bool
log logger.Logger
lock sync.Mutex
}
func (r *Response) withBody(body io.ReadCloser) {
r.body = body
}
func (r *Response) withHeader(headers http.Header) {
r.headers = headers
}
func (r *Response) withStatusCode(code int) {
r.statusCode = code
}
func (r *Response) readBody() {
r.lock.Lock()
defer r.lock.Unlock()
if r.body == nil || r.isRead {
return
}
r.isRead = true
defer r.body.Close()
var bodyReader io.Reader = r.body
// 解压缩
et := HeaderFilterFlags(r.headers.Get(CONTENT_ENCODING_HEADER))
if et != "" {
cp := compressor.GetCompressor(et)
dp, err := cp.Decompress(r.body)
if err != nil {
r.err = err
return
}
bodyReader = dp
}
// 读取数据
body, err := io.ReadAll(bodyReader)
if err != nil {
r.err = err
return
}
r.debug(body)
r.bf = body
}
func (r *Response) debug(body []byte) {
r.log.Debugf("Status Code: %d", r.statusCode)
r.log.Debugf("Response Headers:")
for k, v := range r.headers {
r.log.Debugf("%s=%s", k, strings.Join(v, ","))
}
r.log.Debugf("Body: %s", string(body))
}
func (r *Response) Header(header string, v *string) *Response {
*v = r.headers.Get(header)
return r
}
// 请求正常的情况下, 获取返回的数据, 不做解析
func (r *Response) Raw() ([]byte, error) {
if err := r.Error(); err != nil {
return nil, err
}
return r.bf, r.err
}
// 直接返回stream, 常用于websocket
func (r *Response) Stream() (io.ReadCloser, error) {
return r.body, r.err
}
// 请求正常的情况下, 获取返回的数据, 会根据Content-Type做解析
func (r *Response) Into(v any) error {
if err := r.Error(); err != nil {
return err
}
// 解析数据
ct := HeaderFilterFlags(r.headers.Get(CONTENT_TYPE_HEADER))
nt := negotiator.GetNegotiator(ct)
return nt.Decode(r.bf, v)
}
// 不处理返回, 直接判断请求是否正常
func (r *Response) Error() error {
r.readBody()
// 判断status code
if r.statusCode/100 != 2 {
r.err = fmt.Errorf("status code is %d, not 2xx, response: %s", r.statusCode, string(r.bf))
}
return r.err
}