http 请求库 gout v0.0.10 版本,增加新特性

2020-03-31 09:28:48 +08:00
 guonaihong

gout

gout 是 go 写的 http 客户端,为提高工作效率而开发

地址

https://github.com/guonaihong/gout

构架

feature

演示

<details>

</details>

内容

Installation

go get github.com/guonaihong/gout

example

examples 目录下面的例子,都是可以直接跑的。如果觉得运行例子还是不明白用法,可以把你迷惑的地方写出来,然后提issue

运行命令如下

cd _example
# GOPROXY 是打开 go module 代理,可以更快下载模块
# 第一次运行需要加 GOPROXY 下载模块,模块已的直接 go run 01-color-json.go 即可
env GOPROXY=https://goproxy.cn go run 01-color-json.go

quick start

package main

import (
   "fmt"
   "github.com/guonaihong/gout"
   "time"
)

// 用于解析 服务端 返回的 http body
type RspBody struct {
   ErrMsg  string `json:"errmsg"`
   ErrCode int    `json:"errcode"`
   Data    string `json:"data"`
}

// 用于解析 服务端 返回的 http header
type RspHeader struct {
   Sid  string `header:"sid"`
   Time int    `header:"time"`
}

func main() {
   rsp := RspBody{}
   header := RspHeader{}

   //code := 0
   err := gout.

   	// POST 请求
   	POST("127.0.0.1:8080").

   	// 打开 debug 模式
   	Debug(true).

   	// 设置查询字符串
   	SetQuery(gout.H{"page": 10, "size": 10}).

   	// 设置 http header
   	SetHeader(gout.H{"X-IP": "127.0.0.1", "sid": fmt.Sprintf("%x", time.Now().UnixNano())}).

   	// SetJSON 设置 http body 为 json
   	// 同类函数有 SetBody, SetYAML, SetXML, SetForm, SetWWWForm
   	SetJSON(gout.H{"text": "gout"}).

   	// BindJSON 解析返回的 body 内容
   	// 同类函数有 BindBody, BindYAML, BindXML
   	BindJSON(&rsp).

   	// 解析返回的 http header
   	BindHeader(&header).
   	// http code
   	// Code(&code).

   	// 结束函数
   	Do()

   	// 判度错误
   if err != nil {
   	fmt.Printf("send fail:%s\n", err)
   }
}

/*
> POST /?page=10&size=10 HTTP/1.1
> Sid: 15d9b742ef32c130
> X-Ip: 127.0.0.1
> Content-Type: application/json
>

{
   "text": "gout"
}


*/

API examples

GET POST PUT DELETE PATH HEAD OPTIONS

package main

import (
	"github.com/guonaihong/gout"
)

func main() {
	url := "https://github.com"
	// 发送 GET 方法
	gout.GET(url).Do()

	// 发送 POST 方法
	gout.POST(url).Do()

	// 发送 PUT 方法
	gout.PUT(url).Do()

	// 发送 DELETE 方法
	gout.DELETE(url).Do()

	// 发送 PATH 方法
	gout.PATCH(url).Do()

	// 发送 HEAD 方法
	gout.HEAD(url).Do()

	// 发送 OPTIONS
	gout.OPTIONS(url).Do()
}

Query Parameters

SetQuery

package main

import (
    "fmt"
    "github.com/guonaihong/gout"
    "time"
)

func main() {
    err := gout.
        //设置 GET 请求和 url,:8080/test.query 是 127.0.0.1:8080/test.query 的简写
        GET(":8080/test.query").
        //打开 debug 模式
        Debug(true).
        //设置查询字符串
        SetQuery(gout.H{
            "q1": "v1",
            "q2": 2,
            "q3": float32(3.14),
            "q4": 4.56,
            "q5": time.Now().Unix(),
            "q6": time.Now().UnixNano(),
            "q7": time.Now().Format("2006-01-02")}).
        //结束函数
        Do()
    if err != nil {
        fmt.Printf("%s\n", err)
        return
    }

}

/*
> GET /test.query?q1=v1&q2=2&q3=3.14&q4=4.56&q5=1574081600&q6=1574081600258009213&q7=2019-11-18 HTTP/1.1
>

< HTTP/1.1 200 OK
< Content-Length: 0
*/


SetQuery 支持的更多数据类型

<details>
package main

import (
	"github.com/guonaihong/gout"
)

func main() {

	code := 0

	err := gout.

		//发送 GET 请求 :8080/testquery 是 127.0.0.1:8080/testquery 简写
		GET(":8080/testquery").

		// 设置查询字符串
		SetQuery( /*看下面支持的情况*/ ).

		//解析 http code,如不关心服务端返回状态吗,不设置该函数即可
		Code(&code).
		Do()
	if err != nil {

	}
}



/*
SetQuery 支持的类型有
* string
* map[string]interface{},可以使用 gout.H 别名
* struct
* array, slice(长度必须是偶数)
*/

// 1.string
SetQuery("check_in=2019-06-18&check_out=2018-06-18")

// 2.gout.H 或者 map[string]interface{}
SetQuery(gout.H{
    "check_in":"2019-06-18",
    "check_out":"2019-06-18",
})

// 3.struct
type testQuery struct {
    CheckIn string `query:checkin`
    CheckOut string `query:checkout`
}

SetQuery(&testQuery{CheckIn:2019-06-18, CheckOut:2019-06-18})

// 4.array or slice
// ?active=enable&action=drop
SetQuery([]string{"active", "enable", "action", "drop"})`
</details>

http header

Set request header

package main

import (
    "fmt"
    "github.com/guonaihong/gout"
    "time"
)

func main() {
    err := gout.
        //设置 GET 请求和 url,:8080/test.header 是 127.0.0.1:8080/test.header 的简写
        GET(":8080/test.header").
        //设置 debug 模式
        Debug(true).
        //设置请求 http header
        SetHeader(gout.H{
            "h1": "v1",
            "h2": 2,
            "h3": float32(3.14),
            "h4": 4.56,
            "h5": time.Now().Unix(),
            "h6": time.Now().UnixNano(),
            "h7": time.Now().Format("2006-01-02")}).
        Do()
    if err != nil {
        fmt.Printf("%s\n", err)
        return
    }

}

/*
> GET /test.header HTTP/1.1
> H2: 2
> H3: 3.14
> H4: 4.56
> H5: 1574081686
> H6: 1574081686471347098
> H7: 2019-11-18
> H1: v1
>


< HTTP/1.1 200 OK
< Content-Length: 0
*/

Parsing the response header

package main

import (
    "fmt"
    "github.com/guonaihong/gout"
    "time"
)

// 和解析 json 类似,如要解析 http header 需设置 header tag
type rspHeader struct {
    Total int       `header:"total"`
    Sid   string    `header:"sid"`
    Time  time.Time `header:"time" time_format:"2006-01-02"`
}

func main() {

    rsp := rspHeader{}
    err := gout.
        // :8080/test.header 是 http://127.0.0.1:8080/test.header 的简写
        GET(":8080/test.header").
        //打开 debug 模式
        Debug(true).
        //解析请求 header 至结构体中
        BindHeader(&rsp). 
        //结束函数
        Do()
    if err != nil {
        fmt.Printf("%s\n", err)
        return
    }

    fmt.Printf("rsp header:\n%#v \nTime:%s\n", rsp, rsp.Time)
}

/*
> GET /test.header HTTP/1.1
>



< HTTP/1.1 200 OK
< Content-Length: 0
< Sid: 1234
< Time: 2019-11-18
< Total: 2048
*/

SetHeader 和 BindHeader 支持的更多类型

<details>
package main

import (
    "fmt"
    "github.com/guonaihong/gout"
)

type testHeader struct {
    CheckIn  string `header:checkin`
    CheckOut string `header:checkout`
}

func main() {

    t := testHeader{}

    code := 0

    err := gout.
        GET(":8080/testquery").
        Code(&code).
        SetHeader( /*看下面支持的类型*/ ).
        BindHeader(&t).
        Do()
    if err != nil {
        fmt.Printf("fail:%s\n", err)
    }   
}

// struct
type testHeader struct {
    CheckIn string `header:checkin`
    CheckOut string `header:checkout`
}
/*
map[string]interface{},可以使用 gout.H 别名
struct
array, slice(长度必须是偶数)
*/

// gout.H 或者 map[string]interface{}
SetHeader(gout.H{
    "check_in":"2019-06-18",
    "check_out":"2019-06-18",
})

// struct
type testHeader struct {
    CheckIn string `header:checkin`
    CheckOut string `header:checkout`
}

SetHeader(&testHeader{CheckIn:2019-06-18, CheckOut:2019-06-18})

// array or slice
// -H active:enable -H action:drop
SetHeader([]string{"active", "enable", "action", "drop"})
</details>

http body

body

Set the data to the http request body

// SetBody 设置 string, []byte 等类型数据到 http body 里面
// SetBody 支持的更多数据类型可看下面
package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

func main() {
	err := gout.
		// 设置 POST 方法和 url
		POST(":8080/req/body").
		//打开 debug 模式
		Debug(true).
		// 设置非结构化数据到 http body 里面
		// 设置 json 需使用 SetJSON
		SetBody("send string").
		//结束函数
		Do()

	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}

}

/*
> POST /req/body HTTP/1.1
>

send string

< HTTP/1.1 200 OK
< Content-Type: text/plain; charset=utf-8
< Content-Length: 2

*/

Parse the response body into a variable

// BindBody bind body 到 string, []byte 等类型变量里面
package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

func main() {
	s := ""
	err := gout.
		// 设置 GET 方法及 url
		GET("www.baidu.com").
		// 绑定返回值
		BindBody(&s).
		// 结束函数
		Do()

	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}

	fmt.Printf("html size = %d\n", len(s))
}

支持的类型有

明确不支持的类型有

json

Serialize json to request body

更多支持数据类型及用法

package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

func main() {
	err := gout.POST(":8080/colorjson").
		//打开 debug 模式
		Debug(true).
		//设置 json 到请求 body
		SetJSON(
			gout.H{
				"str":   "foo",
				"num":   100,
				"bool":  false,
				"null":  nil,
				"array": gout.A{"foo", "bar", "baz"},
				"obj":   gout.H{"a": 1, "b": 2},
			},
		).
		Do()

	if err != nil {
		fmt.Printf("err = %v\n", err)
	}
}

/*
> POST /colorjson HTTP/1.1
> Content-Type: application/json
>

{
    "array": [
        "foo",
        "bar",
        "baz"
    ],
    "bool": false,
    "null": null,
    "num": 100,
    "obj": {
        "a": 1,
        "b": 2
    },
    "str": "foo"
}
*/

Parsed http response body in json format

package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

type rsp struct {
	ErrMsg  string `json:"errmsg"`
	ErrCode int    `json:"errcode"`
}

func main() {
	rsp := rsp{}
	err := gout.
		GET(":8080/colorjson").
		//打开 debug 模式
		Debug(true).
		//绑定响应 json 数据到结构体
		BindJSON(&rsp).
		//结束函数
		Do()

	if err != nil {
		fmt.Printf("err = %v\n", err)
	}
}

yaml

发送 yaml 到服务端,然后把服务端返回的 yaml 结果解析到结构体里面

type data struct {
    Id int `yaml:"id"`
    Data string `yaml:"data"`
}


var d1, d2 data
var httpCode int 


err := gout.POST(":8080/test.yaml").SetYAML(&d1).BindYAML(&d2).Code(&httpCode).Do()
if err != nil || httpCode != 200{
    fmt.Printf("send fail:%s\n", err)
}

xml

发送 xml 到服务端,然后把服务端返回的 xml 结果解析到结构体里面

type data struct {
    Id int `xml:"id"`
    Data string `xml:"data"`
}


var d1, d2 data
var httpCode int 


err := gout.POST(":8080/test.xml").SetXML(&d1).BindXML(&d2).Code(&httpCode).Do()
if err != nil || httpCode != 200{
    fmt.Printf("send fail:%s\n", err)
}

form-data

客户端发送 multipart/form-data 到服务端,curl 用法等同 go 代码

curl -F mode=A -F text="good" -F voice=@./test.pcm -f voice2=@./test2.pcm url
package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

func main() {

	code := 0
	err := gout.
		POST(":8080/test").
		// 打开 debug 模式
		Debug(true).
		SetForm(
			gout.H{
				"mode": "A",
				"text": "good",
				// 从文件里面打开
				"voice":  gout.FormFile("test.pcm"),
				"voice2": gout.FormMem("pcm"),
			},
		).
		//解析 http code,如不关心可以不设置
		Code(&code).
		Do()

	if err != nil {
		fmt.Printf("%s\n", err)
	}

	if code != 200 {
	}
}

/*
> POST /test HTTP/1.1
> Content-Type: multipart/form-data; boundary=2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8
>

--2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8
Content-Disposition: form-data; name="mode"

A
--2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8
Content-Disposition: form-data; name="text"

good
--2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8
Content-Disposition: form-data; name="voice"; filename="voice"
Content-Type: application/octet-stream

pcm pcm pcm

--2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8
Content-Disposition: form-data; name="voice2"; filename="voice2"
Content-Type: application/octet-stream

pcm
--2b0685e5b98e540f80b247d5e7c1283807aa07e62b827543859a6db765a8--


< HTTP/1.1 200 OK
< Server: gurl-server
< Content-Length: 0
*/
 
type testForm struct {
    Mode string `form:"mode"`
    Text string `form:"text"`
    Voice string `form:"voice" form-file:"true"` //从文件中读取 
    Voice2 []byte `form:"voice2" form-file:"mem"`  //从内存中构造
}

type rsp struct{
    ErrMsg string `json:"errmsg"`
    ErrCode int `json:"errcode"`
}

t := testForm{}
r := rsp{}
code := 0

err := gout.POST(url).SetForm(&t).ShoudBindJSON(&r).Code(&code).Do()
if err != nil {

}

x-www-form-urlencoded

package main

import (
	"fmt"
	"github.com/guonaihong/gout"
)

func main() {

	code := 0
	err := gout.
		POST(":8080/post").
		// 打开 debug 模式
		Debug(true).
		// 设置 x-www-form-urlencoded 数据
		SetWWWForm(
			gout.H{
				"int":     3,
				"float64": 3.14,
				"string":  "test-www-Form",
			},
		).
		// 关心 http code 返回值设置
		Code(&code).
		Do()
	if err != nil {
		fmt.Printf("%s\n", err)
		return
	}

	if code != 200 {
	}
}

/*
> POST /post HTTP/1.1
> Content-Type: application/x-www-form-urlencoded
>

float64=3.14&int=3&string=test-www-Form

< HTTP/1.1 200 OK
< Content-Length: 0
< Server: gurl-server

*/

callback

callback 主要用在,服务端会返回多种格式 body 的场景, 比如 404 返回的是 html, 200 返回 json 。 这时候要用 Callback 挂载多种处理函数,处理不同的数据结构


func main() {
	
	r, str404 := Result{}, ""
	code := 0

	err := gout.GET(":8080").Callback(func(c *gout.Context) (err error) {

		switch c.Code {
		case 200: //http code 为 200 时,服务端返回的是 json 结构
			c.BindJSON(&r)
		case 404: //http code 为 404 时,服务端返回是 html 字符串
			c.BindBody(&str404)
		}
		code = c.Code
		return nil

	}).Do()

	if err != nil {
		fmt.Printf("err = %s\n", err)
		return
	}

	fmt.Printf("http code = %d, str404(%s) or json result(%v)\n", code, str404, r)

}

Set request timeout

setimeout 是 request 级别的超时方案。相比 http.Client 级别,更灵活。

package main

import (
	"fmt"
	"github.com/guonaihong/gout"
	"time"
)

func main() {
	err := gout.GET(":8080").
		SetTimeout(2 * time.Second).
		Do()

	if err != nil {
		fmt.Printf("err = %v\n", err)
	}
}

569 次点击
所在节点    程序员
2 条回复
wsseo
2020-03-31 11:23:29 +08:00
点个赞👍
guonaihong
2020-03-31 12:59:22 +08:00
@wsseo 感谢支持。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/657815

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX