package main
import (
"fmt"
"log"
"github.com/winterssy/gjson"
)
const dummyData = `
{
"code": 200,
"data": {
"list": [
{
"artist": "周杰伦",
"album": "周杰伦的床边故事",
"name": "告白气球"
},
{
"artist": "周杰伦",
"album": "说好不哭 (with 五月天阿信)",
"name": "说好不哭 (with 五月天阿信)"
}
]
}
}
`
type S struct {
Code int `json:"code"`
Data gjson.Object `json:"data"`
}
func main() {
// 直接解析到 gjson.Object
obj, err := gjson.ParseFromString(dummyData)
if err != nil {
log.Fatal(err)
}
fmt.Println(obj.GetNumber("code"))
fmt.Println(obj.GetArray("data", "list").Index(0).ToObject().GetString("name"))
// Output:
// 200
// 告白气球
var s S
// 绑定到结构体
err = gjson.UnmarshalFromString(dummyData, &s)
if err != nil {
log.Fatal(err)
}
fmt.Println(s.Code)
fmt.Println(s.Data.GetArray("list").Index(0).ToObject().GetString("name"))
// Output:
// 200
// 告白气球
}
// 设置查询参数
ghttp.Post("https://httpbin.org/post",
ghttp.WithQuery(ghttp.Params{
"k1": "v1",
"k2": "v2",
}),
)
// 设置请求头
ghttp.Post("https://httpbin.org/post",
ghttp.WithHeaders(ghttp.Headers{
"k1": "v1",
"k2": "v2",
}),
)
// 发送 Form 表单
ghttp.Post("https://httpbin.org/post",
ghttp.WithForm(ghttp.Form{
"k1": "v1",
"k2": "v2",
}),
)
// 上传文件
ghttp.Post("https://httpbin.org/post",
ghttp.WithFiles(ghttp.Files{
"file1": ghttp.MustOpen("/path/to/testfile1.txt"),
"file2": ghttp.MustOpen("/path/to/testfile2.txt"),
"file3": ghttp.FileFromReader(strings.NewReader("some,data,to,send\nanother,row,to,send\n")).WithFilename("report.csv"),
}),
)
ghttp.Post("https://api.example.com/login",
ghttp.WithBasicAuth("user", "p@ssw$"),
ghttp.EnableRetry(),
)
// 自定义最大尝试次数
ghttp.Post("https://api.example.com/login",
ghttp.WithBasicAuth("user", "p@ssw$"),
ghttp.EnableRetry(ghttp.WithRetryMaxAttempts(5)),
)
// 自定义回退算法
ghttp.Post("https://api.example.com/login",
ghttp.WithBasicAuth("user", "p@ssw$"),
ghttp.EnableRetry(ghttp.WithRetryBackoff(ghttp.NewFibonacciBackoff(30, time.Second))),
)
// 自定义触发器
ghttp.Post("https://api.example.com/login",
ghttp.WithBasicAuth("user", "p@ssw$"),
ghttp.EnableRetry(ghttp.WithRetryTriggers(func(resp *ghttp.Response, err error) bool {
return err != nil || resp.StatusCode != 200
})),
)
// 全局请求头
ghttp.DefaultClient.RegisterBeforeRequestCallbacks(
ghttp.WithUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"),
ghttp.WithReferer("https://www.google.com"),
)
// 全局重试策略
ghttp.DefaultClient.RegisterBeforeRequestCallbacks(ghttp.EnableRetry())
// 反向代理
withReverseProxy := func(target string) ghttp.RequestHook {
return func(req *ghttp.Request) error {
u, err := url.Parse(target)
if err != nil {
return err
}
req.URL.Scheme = u.Scheme
req.URL.Host = u.Host
req.Host = u.Host
req.SetOrigin(u.Host)
return nil
}
}
ghttp.DefaultClient.RegisterBeforeRequestCallbacks(withReverseProxy("https://httpbin.org"))
ghttp.Get("/get")
ghttp.Post("/post")
ghttp.Put("/put")
ghttp.Patch("/patch")
ghttp.Delete("/delete")
// 速率限制
ghttp.DefaultClient.EnableRateLimiting(rate.NewLimiter(1, 10))
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ghttp.Get("https://www.example.com")
}()
}
wg.Wait()
// 限制最大并发数
ghttp.DefaultClient.SetMaxConcurrency(32)
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
ghttp.Get("https://www.example.com")
}()
}
wg.Wait()
ghttp.DefaultClient.EnableDebugging(os.Stdout, true)
ghttp.Post("https://httpbin.org/post",
ghttp.WithForm(ghttp.Form{
"k1": "v1",
"k2": "v2",
}),
)
// Output:
// > POST /post HTTP/1.1
// > Host: httpbin.org
// > Content-Type: application/x-www-form-urlencoded
// >
// k1=v1&k2=v2
// < HTTP/2.0 200 OK
// < Access-Control-Allow-Origin: *
// < Access-Control-Allow-Credentials: true
// < Date: Tue, 03 Mar 2020 14:17:30 GMT
// < Content-Type: application/json
// < Content-Length: 422
// < Server: gunicorn/19.9.0
// <
// {
// "args": {},
// "data": "",
// "files": {},
// "form": {
// "k1": "v1",
// "k2": "v2"
// },
// "headers": {
// "Accept-Encoding": "gzip",
// "Content-Length": "0",
// "Content-Type": "application/x-www-form-urlencoded",
// "Host": "httpbin.org",
// "User-Agent": "Go-http-client/2.0",
// "X-Amzn-Trace-Id": "Root=1-5e5e66fa-46092511ae526478bf2e637f"
// },
// "json": null,
// "origin": "8.8.8.8",
// "url": "https://httpbin.org/post"
// }
ghttp
保留了 net/http
的使用习惯,你可以快速地从标准库迁移。
ghttp.Client
client := ghttp.New()
// Now you can manipulate client like net/http
client.CheckRedirect = ghttp.NoRedirect
client.Timeout = 300 * time.Second
ghttp.Request
req, err := ghttp.NewRequest("GET", "https://httpbin.org/get")
if err != nil {
log.Fatal(err)
}
// Now you can manipulate req like net/http
req.Close = true
ghttp.Response
resp, err := ghttp.Get("https://www.google.com")
if err != nil {
log.Fatal(err)
}
// Now you can access resp like net/http
fmt.Println(resp.StatusCode)
ghttp
没有晦涩难懂的代码,同时具备完整的 API 文档和非常高的测试覆盖率,如果你对某 API 的用法感到困惑,可参考文档中的例程 /测试用例。
1
huson 2020-03-04 01:09:00 +08:00
看来不错 收藏了
|
2
lxml 2020-03-04 01:35:08 +08:00 via Android
ghttp 很适合我的需求
|
3
blless 2020-03-04 01:46:50 +08:00 via Android
gjson 应该跟某个大牛的库重名了,那个库我觉得更强大一点,而且性能贼强
github.com/tidwall/gjson |
4
winterssy OP @blless #3 二者是不一样的,这里的 gjson 本质上是反序列化到 map[string]interface{} 并提供了友好的 API 获取 map 中的字段而已,本质上还是调用了标准库,而 tidwall/gjson 是一个 json-parser。
|
5
lance6716 2020-03-04 09:41:43 +08:00 via Android
官方库是有多难用…整天看到轮子
|
6
winterssy OP @lance6716 通篇也没说官方库难用吧,再说这本来就基于标准库。我写给自己用的,分享给需要的人,不喜你当路过就行了
|
7
blless 2020-03-04 13:23:35 +08:00 via Android
@winterssy 这么一说我倒是想起来 go-jsoniter 有个 Any 类型 API,跟你这个功能也类似,但是官方自己实现性能不是很好,我用 todwall 的 gjson 封装实现了一个 Any 接口 感觉挺好用的
|
8
pkwenda 2020-03-04 14:20:39 +08:00
自己造的轮子,有空学习下
|
9
winterssy OP @blless #7 捣鼓这玩意只是为了省事而已(有的时候不希望反序列化到结构体)。gjson 兼容 encoding/json 和 jsoniter,追求性能的话可切换 jsoniter 进行构建的( go build -tags=jsoniter .)
|
11
wsseo 2020-03-06 14:22:58 +08:00
有机会用一下
|
12
linvaux 2020-03-08 18:36:48 +08:00
go 的这个包管理我是到现在都接受不了
|
13
Aether 2020-03-08 18:58:44 +08:00
虽然如此,但正文里还是预先提一下这是自己的作品不是更好吗?
|