平时开发过程中,开发http请求工具类,甚至http压测模拟都是开发人员的加长便饭,go语言种,虽然已经为开发人员提供方便的http库,但在实际开发中,依然有很多冗余代码,在一些复杂请求中,也需要很多的开发量,此时你要这样想,你遇到的问题,大家也会遇到,这时找找工具类,或者一些库什么的,会起到事半功倍的作用,这不,笔者发现了一个http请求封装的库gout,小而巧,号称瑞士军刀。

  1. https://github.com/guonaihong/gout

Go原生的Http的请求

我们采用go原生的http发送一个get和一个post请求,来看go原生http需要编写那些代码,当需要cookie或者一些其他参数时代码将会下面的代码成倍增加,而且需要我们学习更多的原生api,成本也会增加

  1. func HttpGet() {
  2. res, err := http.Get("http://www.baidu.com")
  3. checkErr(err)
  4. //将http请求相应的内容复制到标准输出(控制台)
  5. io.Copy(os.Stdout, res.Body)
  6. defer res.Body.Close()
  7. }
  8. func HttpPort() {
  9. res, err := http.Post("http://www.baidu.com",
  10. "application/x-www-form-urlencoded", strings.NewReader("name=spw&pwd=123"))
  11. checkErr(err)
  12. io.Copy(os.Stdout, res.Body)
  13. defer res.Body.Close()
  14. }

Gout的示例

gout提供了非常方便链式api,封装了很多内部细节,对于研发人员常用的一些场景都做了非常不做的支持,而且还提供了debug,压测,追踪,重试,自定义等更多功能,下面带领大家一起体验下

一些简单的使用场景 ,Get,Post,Delete方法,如下代码,每种方法代表i中HTTP请求的methd, .do表示开始发送请求,至此一个HTTP请求就发送完毕

  1. func main() {
  2. url := "https://github.com"
  3. // 发送GET方法
  4. gout.GET(url).Do()
  5. // 发送POST方法
  6. gout.POST(url).Do()
  7. // 发送PUT方法
  8. gout.PUT(url).Do()
  9. // 发送DELETE方法
  10. gout.DELETE(url).Do()
  11. // 发送PATH方法
  12. gout.PATCH(url).Do()
  13. // 发送HEAD方法
  14. gout.HEAD(url).Do()
  15. // 发送OPTIONS
  16. gout.OPTIONS(url).Do()
  17. }

上面的代码问题很明显,怎么获取结果呢?错误了怎么办呢?,下面看一个GET的示例,声明一个result字符串变量,代表http返回的内容,通过BindBody把返回的结果绑定到result变量中,这个一个完整的请求就OK了,同时http请求结果的绑定还支持json,yam,xml,流等格式,主要方法就是BindJSON,BondXML,方法命名方式以此类推

  1. //GET请求发送
  2. func StudyGoutGet() {
  3. result := ""
  4. // 发送GET方法
  5. err := gout.GET(url).BindBody(&result).Do()
  6. fmt.Println(err,result)
  7. }
  8. //POST 请求发送
  9. func StudyGoutPost() {
  10. result := ""
  11. // 发送GET方法
  12. err := gout.POST(url).BindBody(&result).Do()
  13. fmt.Println(err,result)
  14. }

我们了解了请求的发送,返回值的绑定,那么传参该怎么穿呢?支持哪些格式,一起来看看,我们支持GET请求直接在url后面拼接字符串就可以,Gout同时也支持设置参数方法

  1. func StudyGoutGetAndParam() {
  2. err := gout.
  3. //设置GET请求和url,:8080/test.query是127.0.0.1:8080/test.query的简写
  4. GET(":8080/test.query").
  5. //设置查询字符串
  6. SetQuery(gout.H{
  7. "q1": "v1",
  8. "q2": 2,
  9. "q3": float32(3.14),
  10. "q4": time.Now().Format("2006-01-02")}).
  11. //结束函数
  12. Do()
  13. if err != nil {
  14. fmt.Printf("%s\n", err)
  15. return
  16. }
  17. }
  18. //对于POST请求,支持的参数设置方法就更多,JSON
  19. func StudyGoutPostAndParam() {
  20. err := gout.
  21. POST("127.0.0.1:8080").
  22. // 设置查询字符串
  23. SetQuery(gout.H{"page": 10, "size": 10}).
  24. // 设置http header
  25. SetHeader(gout.H{"X-IP": "127.0.0.1", "sid": fmt.Sprintf("%x", time.Now().UnixNano())}).
  26. // SetJSON设置http body为json
  27. // 同类函数有SetBody, SetYAML, SetXML, SetForm, SetWWWForm
  28. SetJSON(gout.H{"text": "gout"}).
  29. // 结束函数
  30. Do()
  31. // 判度错误
  32. if err != nil {
  33. fmt.Printf("send fail:%s\n", err)
  34. }
  35. }

除了上面这些简单的查询,gout还支持回调处理,debug模式,trace跟踪,压测模拟等众多特性,一起看看这些特性,回调处理处理指的是针对http返回结果的不同code做出不同的处理结果,debug模式下会打印处理http发送请求时一些head信息,方便开发人员问题排查,trace跟踪会打印http请求各阶段的耗时,包括链接,处理,相应等,压测模拟指的是我们可以很方便的对一个http接口发起压测,同时统计压测结果。

  1. //请求回调处理
  2. func StudyGoutCallBack() {
  3. result := ""
  4. // 发送GET方法,对返回的结果进行回调处理,可以判断http的code码做出不同的处理
  5. err := gout.GET("http://wwww.baidu.com").Callback(func(context *dataflow.Context) error {
  6. switch context.Code {
  7. case 200:
  8. context.BindBody(&result)
  9. case 404:
  10. context.BindBody(&result)
  11. }
  12. return nil
  13. }).Do()
  14. fmt.Println(err, result)
  15. }
  1. //debug设置,debug情况下会打印一些请求head信息,如下截图信息
  2. func StudyGoutGetDebug() {
  3. result := ""
  4. // 发送GET方法
  5. gout.GET(url).Debug(true).BindBody(&result).Do()
  6. fmt.Println(result)
  7. }

image.png

  1. //跟踪请求耗时时间,这个会打印请求各阶段链接耗时
  2. func StudyGoutGetTraceInfo() {
  3. result := ""
  4. // 发送GET方法
  5. gout.GET(url).Debug(gout.Trace()).BindBody(&result).Do()
  6. fmt.Println(result)
  7. }

image.png

  1. // 指定并发数的情况下持续一段时间的压测,会把预测的不同请请求百分比下的平均耗时统计出来,如下截图
  2. func StudyGoutBenchmarkDuration() {
  3. err := gout.
  4. POST(url). //压测本机8080端口
  5. Filter(). //打开过滤器
  6. Bench(). //选择bench功能
  7. Concurrent(20). //并发数
  8. Durations(10 * time.Second). //压测时间
  9. Do()
  10. if err != nil {
  11. fmt.Printf("%v\n", err)
  12. }
  13. }

下面截图告诉了我们QPS/s时810,失败的请求时52个,并发级别是20,持续压测时间10.01s,50%的请求都在20ms内完成,99%的请求都在73ms完成。
image.png

Gout完整的特性

下面这些特性是gout官网的描述,感兴趣的同学可以再细细研究一下,看看源码实现,我相信这个库一定给你的开发效率和工具类带来很多方便,希望帮助到大家

支持设置 GET/PUT/DELETE/PATH/HEAD/OPTIONS
支持设置请求 http header(可传 struct,map,array,slice 等类型)
支持设置 URL query(可传 struct,map,array,slice,string 等类型)
支持设置 json 编码到请求 body 里面(可传struct, map, string, []byte 等类型)
支持设置 xml 编码到请求 body 里面(可传struct, string, []byte 等类型)
支持设置 yaml 编码到请求 body 里面(可传struct, map, string, []byte 等类型)
支持设置 form-data(可传 struct, map, array, slice 等类型)
支持设置 x-www-form-urlencoded(可传 struct,map,array,slice 等类型)
支持设置 io.Reader,uint/uint8/uint16…int/int8…string…[]byte…float32,float64 至请求 body 里面
支持解析响应body里面的json,xml,yaml至结构体里(BindJSON/BindXML/BindYAML)
支持解析响应body的内容至io.Writer, uint/uint8…int/int8…string…[]byte…float32,float64
支持解析响应header至结构体里
支持接口性能benchmark,可控制压测一定次数还是时间,可控制压测频率
支持retry-backoff,可以指定重试条件
支持发送裸http数据包
支持导出curl命令
传入自定义*http.Client
支持请求中间件(https://github.com/antlabs/gout-middleware)
等等更多

一个非常棒的http库,提升开发效率的利器 - 图4