1
0
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:
astaxie 2013-08-03 22:20:09 +08:00
parent f7dd376596
commit c58445c772
22 changed files with 353 additions and 0 deletions

78
docs/zh/HttpLib.md Normal file
View 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)

View File

@ -44,6 +44,7 @@ beego是一个类似tornado的Go应用框架采用了RESTFul的方式来实
* [beego案例](Application.md)
* [热升级](HotUpdate.md)
* [API应用开发入门](API.md)
* [HTTPLIB客户端](HttpLib.md)
# API接口

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

View File

242
httplib.go Normal file
View 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
View 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")
}
}