c58445c7 by astaxie

add httplib support like http.client

1 parent f7dd3765
1 ## 方便的http客户端
2 我们经常会使用Go来请求其他API应用,例如你使用beego开发了一个RESTFul的API应用,那么如果来请求呢?当然可以使用`http.Client`来实现,但是需要自己来操作很多步骤,自己需要考虑很多东西,所以我就基于net下的一些包实现了这个简便的http客户端工具。
3
4 该工具的主要特点:
5
6 - 链式操作
7 - 超时控制
8 - 方便的解析
9 - 可控的debug
10
11 ## 例子
12 我们上次开发的RESTful应用,最后我写过如何通过curl来进行测试,那么下面一一对每个操作如何用httplib来操作进行展示
13
14 - 添加一个对象:
15
16 `curl -X POST -d '{"Score":1337,"PlayerName":"Sean Plott"}' http://127.0.0.1:8080/object`
17
18 返回一个相应的objectID:astaxie1373349756660423900
19
20 str,err:=beego.Post("http://127.0.0.1:8080/object").Body(`{"Score":1337,"PlayerName":"Sean Plott"}`).String()
21 if err != nil{
22 println(err)
23 }
24
25 - 查询一个对象
26
27 `curl -X GET http://127.0.0.1:8080/object/astaxie1373349756660423900`
28
29 var object Obeject
30 err:=beego.Get("http://127.0.0.1:8080/object/astaxie1373349756660423900").ToJson(&object)
31 if err != nil{
32 println(err)
33 }
34
35 - 查询全部的对象
36
37 `curl -X GET http://127.0.0.1:8080/object`
38
39 var objects []Object
40 err:=beego.Get("http://127.0.0.1:8080/object").ToJson(&objects)
41 if err != nil{
42 println(err)
43 }
44
45 - 更新一个对象
46
47 `curl -X PUT -d '{"Score":10000}'http://127.0.0.1:8080/object/astaxie1373349756660423900`
48
49 str,err:=beego.Put("http://127.0.0.1:8080/object/astaxie1373349756660423900").Body(`{"Score":10000}`).String()
50 if err != nil{
51 println(err)
52 }
53
54 - 删除一个对象
55
56 `curl -X DELETE http://127.0.0.1:8080/object/astaxie1373349756660423900`
57
58 str,er:=beego.Delete("http://127.0.0.1:8080/object/astaxie1373349756660423900").String()
59 if err != nil{
60 println(err)
61 }
62
63 ## 开启调试模式
64 用户可以开启调试打印request信息,默认是关闭模式
65
66 beego.Post(url).Debug(true)
67
68 ## ToFile、ToXML、ToJson
69 上面我演示了Json的解析,其实还有直接保存为文件的ToFile操作,解析XML的ToXML操作
70
71
72 ## 设置链接超时和读写超时
73 默认都设置为60秒,用户可以通过函数来设置相应的超时时间
74
75 beego.Get(url).SetTimeout(100*time.Second,100*time.Second)
76
77
78 更加详细的请参考[API接口](http://gowalker.org/github.com/astaxie/beego)
...\ No newline at end of file ...\ No newline at end of file
...@@ -44,6 +44,7 @@ beego是一个类似tornado的Go应用框架,采用了RESTFul的方式来实 ...@@ -44,6 +44,7 @@ beego是一个类似tornado的Go应用框架,采用了RESTFul的方式来实
44 * [beego案例](Application.md) 44 * [beego案例](Application.md)
45 * [热升级](HotUpdate.md) 45 * [热升级](HotUpdate.md)
46 * [API应用开发入门](API.md) 46 * [API应用开发入门](API.md)
47 * [HTTPLIB客户端](HttpLib.md)
47 48
48 49
49 # API接口 50 # API接口
......
1 package beego
2
3 import (
4 "bytes"
5 "encoding/json"
6 "encoding/xml"
7 "io"
8 "io/ioutil"
9 "net"
10 "net/http"
11 "net/http/httputil"
12 "net/url"
13 "os"
14 "strings"
15 "time"
16 )
17
18 var defaultUserAgent = "beegoServer"
19
20 func Get(url string) *BeegoHttpRequest {
21 var req http.Request
22 req.Method = "GET"
23 req.Header = http.Header{}
24 req.Header.Set("User-Agent", defaultUserAgent)
25 return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
26 }
27
28 func Post(url string) *BeegoHttpRequest {
29 var req http.Request
30 req.Method = "POST"
31 req.Header = http.Header{}
32 req.Header.Set("User-Agent", defaultUserAgent)
33 return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
34 }
35
36 func Put(url string) *BeegoHttpRequest {
37 var req http.Request
38 req.Method = "PUT"
39 req.Header = http.Header{}
40 req.Header.Set("User-Agent", defaultUserAgent)
41 return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
42 }
43
44 func Delete(url string) *BeegoHttpRequest {
45 var req http.Request
46 req.Method = "DELETE"
47 req.Header = http.Header{}
48 req.Header.Set("User-Agent", defaultUserAgent)
49 return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
50 }
51
52 func Head(url string) *BeegoHttpRequest {
53 var req http.Request
54 req.Method = "HEAD"
55 req.Header = http.Header{}
56 req.Header.Set("User-Agent", defaultUserAgent)
57 return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
58 }
59
60 type BeegoHttpRequest struct {
61 url string
62 req *http.Request
63 params map[string]string
64 showdebug bool
65 connectTimeout time.Duration
66 readWriteTimeout time.Duration
67 }
68
69 func (b *BeegoHttpRequest) Debug(isdebug bool) *BeegoHttpRequest {
70 b.showdebug = isdebug
71 return b
72 }
73
74 func (b *BeegoHttpRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHttpRequest {
75 b.connectTimeout = connectTimeout
76 b.readWriteTimeout = readWriteTimeout
77 return b
78 }
79
80 func (b *BeegoHttpRequest) Header(key, value string) *BeegoHttpRequest {
81 b.req.Header.Set(key, value)
82 return b
83 }
84
85 func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest {
86 b.params[key] = value
87 return b
88 }
89
90 func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest {
91 switch t := data.(type) {
92 case string:
93 bf := bytes.NewBufferString(t)
94 b.req.Body = ioutil.NopCloser(bf)
95 b.req.ContentLength = int64(len(t))
96 case []byte:
97 bf := bytes.NewBuffer(t)
98 b.req.Body = ioutil.NopCloser(bf)
99 b.req.ContentLength = int64(len(t))
100 }
101 return b
102 }
103
104 func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
105 var paramBody string
106 if b.params != nil && len(b.params) > 0 {
107 var buf bytes.Buffer
108 for k, v := range b.params {
109 buf.WriteString(url.QueryEscape(k))
110 buf.WriteByte('=')
111 buf.WriteString(url.QueryEscape(v))
112 buf.WriteByte('&')
113 }
114 paramBody = buf.String()
115 paramBody = paramBody[0 : len(paramBody)-1]
116 }
117 if b.req.Method == "GET" && len(paramBody) > 0 {
118 if strings.Index(b.url, "?") != -1 {
119 b.url += "&" + paramBody
120 } else {
121 b.url = b.url + "?" + paramBody
122 }
123 } else if b.req.Method == "POST" && b.req.Body == nil && len(paramBody) > 0 {
124 b.Header("Content-Type", "application/x-www-form-urlencoded")
125 b.Body(paramBody)
126 }
127
128 url, err := url.Parse(b.url)
129 if url.Scheme == "" {
130 b.url = "http://" + b.url
131 url, err = url.Parse(b.url)
132 }
133
134 if err != nil {
135 return nil, err
136 }
137 b.req.URL = url
138 if b.showdebug {
139 dump, err := httputil.DumpRequest(b.req, true)
140 if err != nil {
141 println(err.Error())
142 }
143 println(string(dump))
144 }
145
146 client := &http.Client{
147 Transport: &http.Transport{
148 Dial: TimeoutDialer(b.connectTimeout, b.readWriteTimeout),
149 },
150 }
151 resp, err := client.Do(b.req)
152 if err != nil {
153 return nil, err
154 }
155 return resp, nil
156 }
157
158 func (b *BeegoHttpRequest) String() (string, error) {
159 data, err := b.Bytes()
160 if err != nil {
161 return "", err
162 }
163
164 return string(data), nil
165 }
166
167 func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
168 resp, err := b.getResponse()
169 if err != nil {
170 return nil, err
171 }
172 if resp.Body == nil {
173 return nil, nil
174 }
175 defer resp.Body.Close()
176 data, err := ioutil.ReadAll(resp.Body)
177 if err != nil {
178 return nil, err
179 }
180 return data, nil
181 }
182
183 func (b *BeegoHttpRequest) ToFile(filename string) error {
184 f, err := os.Create(filename)
185 if err != nil {
186 return err
187 }
188 defer f.Close()
189
190 resp, err := b.getResponse()
191 if err != nil {
192 return err
193 }
194 if resp.Body == nil {
195 return nil
196 }
197 defer resp.Body.Close()
198 _, err = io.Copy(f, resp.Body)
199 if err != nil {
200 return err
201 }
202 return nil
203 }
204
205 func (b *BeegoHttpRequest) ToJson(v interface{}) error {
206 data, err := b.Bytes()
207 if err != nil {
208 return err
209 }
210 err = json.Unmarshal(data, v)
211 if err != nil {
212 return err
213 }
214 return nil
215 }
216
217 func (b *BeegoHttpRequest) ToXML(v interface{}) error {
218 data, err := b.Bytes()
219 if err != nil {
220 return err
221 }
222 err = xml.Unmarshal(data, v)
223 if err != nil {
224 return err
225 }
226 return nil
227 }
228
229 func (b *BeegoHttpRequest) Response() (*http.Response, error) {
230 return b.getResponse()
231 }
232
233 func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
234 return func(netw, addr string) (net.Conn, error) {
235 conn, err := net.DialTimeout(netw, addr, cTimeout)
236 if err != nil {
237 return nil, err
238 }
239 conn.SetDeadline(time.Now().Add(rwTimeout))
240 return conn, nil
241 }
242 }
1 package beego
2
3 import (
4 "io/ioutil"
5 "testing"
6 )
7
8 func TestGetUrl(t *testing.T) {
9 resp, err := GetUrl("http://beego.me/").Response()
10 if err != nil {
11 t.Fatal(err)
12 }
13 if resp.Body == nil {
14 t.Fatal("body is nil")
15 }
16 data, err := ioutil.ReadAll(resp.Body)
17 defer resp.Body.Close()
18 if err != nil {
19 t.Fatal(err)
20 }
21 if len(data) == 0 {
22 t.Fatal("data is no")
23 }
24
25 str, err := GetUrl("http://beego.me/").String()
26 if err != nil {
27 t.Fatal(err)
28 }
29 if len(str) == 0 {
30 t.Fatal("has no info")
31 }
32 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!