mirror of
https://github.com/astaxie/beego.git
synced 2024-12-22 20:00:50 +00:00
add httplib support like http.client
This commit is contained in:
parent
f7dd376596
commit
c58445c772
78
docs/zh/HttpLib.md
Normal file
78
docs/zh/HttpLib.md
Normal file
@ -0,0 +1,78 @@
|
||||
## 方便的http客户端
|
||||
我们经常会使用Go来请求其他API应用,例如你使用beego开发了一个RESTFul的API应用,那么如果来请求呢?当然可以使用`http.Client`来实现,但是需要自己来操作很多步骤,自己需要考虑很多东西,所以我就基于net下的一些包实现了这个简便的http客户端工具。
|
||||
|
||||
该工具的主要特点:
|
||||
|
||||
- 链式操作
|
||||
- 超时控制
|
||||
- 方便的解析
|
||||
- 可控的debug
|
||||
|
||||
## 例子
|
||||
我们上次开发的RESTful应用,最后我写过如何通过curl来进行测试,那么下面一一对每个操作如何用httplib来操作进行展示
|
||||
|
||||
- 添加一个对象:
|
||||
|
||||
`curl -X POST -d '{"Score":1337,"PlayerName":"Sean Plott"}' http://127.0.0.1:8080/object`
|
||||
|
||||
返回一个相应的objectID:astaxie1373349756660423900
|
||||
|
||||
str,err:=beego.Post("http://127.0.0.1:8080/object").Body(`{"Score":1337,"PlayerName":"Sean Plott"}`).String()
|
||||
if err != nil{
|
||||
println(err)
|
||||
}
|
||||
|
||||
- 查询一个对象
|
||||
|
||||
`curl -X GET http://127.0.0.1:8080/object/astaxie1373349756660423900`
|
||||
|
||||
var object Obeject
|
||||
err:=beego.Get("http://127.0.0.1:8080/object/astaxie1373349756660423900").ToJson(&object)
|
||||
if err != nil{
|
||||
println(err)
|
||||
}
|
||||
|
||||
- 查询全部的对象
|
||||
|
||||
`curl -X GET http://127.0.0.1:8080/object`
|
||||
|
||||
var objects []Object
|
||||
err:=beego.Get("http://127.0.0.1:8080/object").ToJson(&objects)
|
||||
if err != nil{
|
||||
println(err)
|
||||
}
|
||||
|
||||
- 更新一个对象
|
||||
|
||||
`curl -X PUT -d '{"Score":10000}'http://127.0.0.1:8080/object/astaxie1373349756660423900`
|
||||
|
||||
str,err:=beego.Put("http://127.0.0.1:8080/object/astaxie1373349756660423900").Body(`{"Score":10000}`).String()
|
||||
if err != nil{
|
||||
println(err)
|
||||
}
|
||||
|
||||
- 删除一个对象
|
||||
|
||||
`curl -X DELETE http://127.0.0.1:8080/object/astaxie1373349756660423900`
|
||||
|
||||
str,er:=beego.Delete("http://127.0.0.1:8080/object/astaxie1373349756660423900").String()
|
||||
if err != nil{
|
||||
println(err)
|
||||
}
|
||||
|
||||
## 开启调试模式
|
||||
用户可以开启调试打印request信息,默认是关闭模式
|
||||
|
||||
beego.Post(url).Debug(true)
|
||||
|
||||
## ToFile、ToXML、ToJson
|
||||
上面我演示了Json的解析,其实还有直接保存为文件的ToFile操作,解析XML的ToXML操作
|
||||
|
||||
|
||||
## 设置链接超时和读写超时
|
||||
默认都设置为60秒,用户可以通过函数来设置相应的超时时间
|
||||
|
||||
beego.Get(url).SetTimeout(100*time.Second,100*time.Second)
|
||||
|
||||
|
||||
更加详细的请参考[API接口](http://gowalker.org/github.com/astaxie/beego)
|
@ -44,6 +44,7 @@ beego是一个类似tornado的Go应用框架,采用了RESTFul的方式来实
|
||||
* [beego案例](Application.md)
|
||||
* [热升级](HotUpdate.md)
|
||||
* [API应用开发入门](API.md)
|
||||
* [HTTPLIB客户端](HttpLib.md)
|
||||
|
||||
|
||||
# API接口
|
||||
|
0
docs/zh/quickstart/cache.md
Normal file
0
docs/zh/quickstart/cache.md
Normal file
0
docs/zh/quickstart/configs.md
Normal file
0
docs/zh/quickstart/configs.md
Normal file
0
docs/zh/quickstart/controller.md
Normal file
0
docs/zh/quickstart/controller.md
Normal file
0
docs/zh/quickstart/createapp.md
Normal file
0
docs/zh/quickstart/createapp.md
Normal file
0
docs/zh/quickstart/deploy.md
Normal file
0
docs/zh/quickstart/deploy.md
Normal file
0
docs/zh/quickstart/devmode.md
Normal file
0
docs/zh/quickstart/devmode.md
Normal file
0
docs/zh/quickstart/filter.md
Normal file
0
docs/zh/quickstart/filter.md
Normal file
0
docs/zh/quickstart/flash.md
Normal file
0
docs/zh/quickstart/flash.md
Normal file
0
docs/zh/quickstart/logs.md
Normal file
0
docs/zh/quickstart/logs.md
Normal file
0
docs/zh/quickstart/miniapp.md
Normal file
0
docs/zh/quickstart/miniapp.md
Normal file
0
docs/zh/quickstart/params.md
Normal file
0
docs/zh/quickstart/params.md
Normal file
0
docs/zh/quickstart/request.md
Normal file
0
docs/zh/quickstart/request.md
Normal file
0
docs/zh/quickstart/response.md
Normal file
0
docs/zh/quickstart/response.md
Normal file
0
docs/zh/quickstart/router.md
Normal file
0
docs/zh/quickstart/router.md
Normal file
0
docs/zh/quickstart/session.md
Normal file
0
docs/zh/quickstart/session.md
Normal file
0
docs/zh/quickstart/staticfile.md
Normal file
0
docs/zh/quickstart/staticfile.md
Normal file
0
docs/zh/quickstart/template.md
Normal file
0
docs/zh/quickstart/template.md
Normal file
0
docs/zh/quickstart/third.md
Normal file
0
docs/zh/quickstart/third.md
Normal file
242
httplib.go
Normal file
242
httplib.go
Normal file
@ -0,0 +1,242 @@
|
||||
package beego
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var defaultUserAgent = "beegoServer"
|
||||
|
||||
func Get(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "GET"
|
||||
req.Header = http.Header{}
|
||||
req.Header.Set("User-Agent", defaultUserAgent)
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
|
||||
}
|
||||
|
||||
func Post(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "POST"
|
||||
req.Header = http.Header{}
|
||||
req.Header.Set("User-Agent", defaultUserAgent)
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
|
||||
}
|
||||
|
||||
func Put(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "PUT"
|
||||
req.Header = http.Header{}
|
||||
req.Header.Set("User-Agent", defaultUserAgent)
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
|
||||
}
|
||||
|
||||
func Delete(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "DELETE"
|
||||
req.Header = http.Header{}
|
||||
req.Header.Set("User-Agent", defaultUserAgent)
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
|
||||
}
|
||||
|
||||
func Head(url string) *BeegoHttpRequest {
|
||||
var req http.Request
|
||||
req.Method = "HEAD"
|
||||
req.Header = http.Header{}
|
||||
req.Header.Set("User-Agent", defaultUserAgent)
|
||||
return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second}
|
||||
}
|
||||
|
||||
type BeegoHttpRequest struct {
|
||||
url string
|
||||
req *http.Request
|
||||
params map[string]string
|
||||
showdebug bool
|
||||
connectTimeout time.Duration
|
||||
readWriteTimeout time.Duration
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Debug(isdebug bool) *BeegoHttpRequest {
|
||||
b.showdebug = isdebug
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) SetTimeout(connectTimeout, readWriteTimeout time.Duration) *BeegoHttpRequest {
|
||||
b.connectTimeout = connectTimeout
|
||||
b.readWriteTimeout = readWriteTimeout
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Header(key, value string) *BeegoHttpRequest {
|
||||
b.req.Header.Set(key, value)
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest {
|
||||
b.params[key] = value
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Body(data interface{}) *BeegoHttpRequest {
|
||||
switch t := data.(type) {
|
||||
case string:
|
||||
bf := bytes.NewBufferString(t)
|
||||
b.req.Body = ioutil.NopCloser(bf)
|
||||
b.req.ContentLength = int64(len(t))
|
||||
case []byte:
|
||||
bf := bytes.NewBuffer(t)
|
||||
b.req.Body = ioutil.NopCloser(bf)
|
||||
b.req.ContentLength = int64(len(t))
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) getResponse() (*http.Response, error) {
|
||||
var paramBody string
|
||||
if b.params != nil && len(b.params) > 0 {
|
||||
var buf bytes.Buffer
|
||||
for k, v := range b.params {
|
||||
buf.WriteString(url.QueryEscape(k))
|
||||
buf.WriteByte('=')
|
||||
buf.WriteString(url.QueryEscape(v))
|
||||
buf.WriteByte('&')
|
||||
}
|
||||
paramBody = buf.String()
|
||||
paramBody = paramBody[0 : len(paramBody)-1]
|
||||
}
|
||||
if b.req.Method == "GET" && len(paramBody) > 0 {
|
||||
if strings.Index(b.url, "?") != -1 {
|
||||
b.url += "&" + paramBody
|
||||
} else {
|
||||
b.url = b.url + "?" + paramBody
|
||||
}
|
||||
} else if b.req.Method == "POST" && b.req.Body == nil && len(paramBody) > 0 {
|
||||
b.Header("Content-Type", "application/x-www-form-urlencoded")
|
||||
b.Body(paramBody)
|
||||
}
|
||||
|
||||
url, err := url.Parse(b.url)
|
||||
if url.Scheme == "" {
|
||||
b.url = "http://" + b.url
|
||||
url, err = url.Parse(b.url)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b.req.URL = url
|
||||
if b.showdebug {
|
||||
dump, err := httputil.DumpRequest(b.req, true)
|
||||
if err != nil {
|
||||
println(err.Error())
|
||||
}
|
||||
println(string(dump))
|
||||
}
|
||||
|
||||
client := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
Dial: TimeoutDialer(b.connectTimeout, b.readWriteTimeout),
|
||||
},
|
||||
}
|
||||
resp, err := client.Do(b.req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) String() (string, error) {
|
||||
data, err := b.Bytes()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(data), nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Bytes() ([]byte, error) {
|
||||
resp, err := b.getResponse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if resp.Body == nil {
|
||||
return nil, nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) ToFile(filename string) error {
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
resp, err := b.getResponse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if resp.Body == nil {
|
||||
return nil
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) ToJson(v interface{}) error {
|
||||
data, err := b.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = json.Unmarshal(data, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) ToXML(v interface{}) error {
|
||||
data, err := b.Bytes()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = xml.Unmarshal(data, v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BeegoHttpRequest) Response() (*http.Response, error) {
|
||||
return b.getResponse()
|
||||
}
|
||||
|
||||
func TimeoutDialer(cTimeout time.Duration, rwTimeout time.Duration) func(net, addr string) (c net.Conn, err error) {
|
||||
return func(netw, addr string) (net.Conn, error) {
|
||||
conn, err := net.DialTimeout(netw, addr, cTimeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn.SetDeadline(time.Now().Add(rwTimeout))
|
||||
return conn, nil
|
||||
}
|
||||
}
|
32
httplib_test.go
Normal file
32
httplib_test.go
Normal file
@ -0,0 +1,32 @@
|
||||
package beego
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetUrl(t *testing.T) {
|
||||
resp, err := GetUrl("http://beego.me/").Response()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if resp.Body == nil {
|
||||
t.Fatal("body is nil")
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
defer resp.Body.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(data) == 0 {
|
||||
t.Fatal("data is no")
|
||||
}
|
||||
|
||||
str, err := GetUrl("http://beego.me/").String()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(str) == 0 {
|
||||
t.Fatal("has no info")
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user