This repository has been archived by the owner on Apr 26, 2022. It is now read-only.
/
response.go
101 lines (87 loc) · 2.34 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
/*
* @Author: thepoy
* @Email: thepoy@163.com
* @File Name: response.go (c) 2021
* @Created: 2021-07-24 13:34:44
* @Modified: 2021-08-02 18:01:36
*/
package predator
import (
"errors"
"io/ioutil"
"sync"
ctx "github.com/thep0y/predator/context"
"github.com/thep0y/predator/json"
"github.com/valyala/fasthttp"
)
var (
ErrIncorrectResponse = errors.New("the response status code is not 200 or 201")
)
type Response struct {
// 响应状态码
StatusCode int
// 二进制请求体
Body []byte
// 请求和响应之间共享的上下文
Ctx ctx.Context `json:"-"`
// 响应对应的请求
Request *Request `json:"-"`
// 响应头
Headers fasthttp.ResponseHeader
// 是否从缓存中取得的响应
FromCache bool
}
// Save writes response body to disk
func (r *Response) Save(fileName string) error {
return ioutil.WriteFile(fileName, r.Body, 0644)
}
func (r *Response) GetSetCookie() string {
return string(r.Headers.Peek("Set-Cookie"))
}
func (r *Response) ContentType() string {
return string(r.Headers.Peek("Content-Type"))
}
func (r *Response) String() string {
return string(r.Body)
}
func (r *Response) Reset() {
r.StatusCode = 0
if r.Body != nil {
// 将 body 长度截为 0,这样不会删除引用关系,GC 不会回收,
// 可以实现 body 的复用
r.Body = r.Body[:0]
}
ctx.ReleaseCtx(r.Ctx)
ReleaseRequest(r.Request)
r.Headers.Reset()
r.FromCache = false
}
func (r Response) Marshal() ([]byte, error) {
if r.StatusCode != fasthttp.StatusOK && r.StatusCode != fasthttp.StatusCreated {
return nil, ErrIncorrectResponse
}
return json.Marshal(r)
}
var (
responsePool sync.Pool
)
// AcquireResponse returns an empty Response instance from response pool.
//
// The returned Response instance may be passed to ReleaseResponse when it is
// no longer needed. This allows Response recycling, reduces GC pressure
// and usually improves performance.
func AcquireResponse() *Response {
v := responsePool.Get()
if v == nil {
return &Response{}
}
return v.(*Response)
}
// ReleaseResponse returns resp acquired via AcquireResponse to response pool.
//
// It is forbidden accessing resp and/or its' members after returning
// it to response pool.
func ReleaseResponse(resp *Response) {
resp.Reset()
responsePool.Put(resp)
}