add httplib support like http.client
Showing
22 changed files
with
353 additions
and
0 deletions
docs/zh/HttpLib.md
0 → 100644
| 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接口 | ... | ... |
docs/zh/quickstart/cache.md
0 → 100644
File mode changed
docs/zh/quickstart/configs.md
0 → 100644
File mode changed
docs/zh/quickstart/controller.md
0 → 100644
File mode changed
docs/zh/quickstart/createapp.md
0 → 100644
File mode changed
docs/zh/quickstart/deploy.md
0 → 100644
File mode changed
docs/zh/quickstart/devmode.md
0 → 100644
File mode changed
docs/zh/quickstart/filter.md
0 → 100644
File mode changed
docs/zh/quickstart/flash.md
0 → 100644
File mode changed
docs/zh/quickstart/logs.md
0 → 100644
File mode changed
docs/zh/quickstart/miniapp.md
0 → 100644
File mode changed
docs/zh/quickstart/params.md
0 → 100644
File mode changed
docs/zh/quickstart/request.md
0 → 100644
File mode changed
docs/zh/quickstart/response.md
0 → 100644
File mode changed
docs/zh/quickstart/router.md
0 → 100644
File mode changed
docs/zh/quickstart/session.md
0 → 100644
File mode changed
docs/zh/quickstart/staticfile.md
0 → 100644
File mode changed
docs/zh/quickstart/template.md
0 → 100644
File mode changed
docs/zh/quickstart/third.md
0 → 100644
File mode changed
httplib.go
0 → 100644
| 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 | } |
httplib_test.go
0 → 100644
| 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 | } |
-
Please register or sign in to post a comment