简介

gentlemangentlemannet/httpgentleman

快速使用

先安装:

$ go get gopkg.in/h2non/gentleman.v2

后使用:

package mainimport (  "fmt"  "gopkg.in/h2non/gentleman.v2")func main() {  cli := gentleman.New()  cli.URL("https://dog.ceo")  req := cli.Request()  req.Path("/api/breeds/image/random")  req.SetHeader("Client", "gentleman")  res, err := req.Send()  if err != nil {    fmt.Printf("Request error: %vn", err)    return  }  if !res.Ok {    fmt.Printf("Invalid server response: %dn", res.StatusCode)    return  }  fmt.Printf("Body: %s", res.String())}
gentlemanv1v2v2v2gentleman
gentleman.New()cliclicli.URL()cli.Request()reqreq.Path()req.Header()HeaderClientgentlemanreq.Send()resres
public-apishttps://dog.ceo/api/breeds/image/random
Body: {"message":"https://images.dog.ceo/breeds/malamute/n02110063_10567.jpg","status":"success"}
statussuccessmessage

插件

gentlemangentlemangentlemanplugins
body
body
package mainimport (  "fmt"  "gopkg.in/h2non/gentleman.v2"  "gopkg.in/h2non/gentleman.v2/plugins/body")func main() {  cli := gentleman.New()  cli.URL("http://httpbin.org/post")  data := map[string]string{"foo": "bar"}  cli.Use(body.JSON(data))  req := cli.Request()  req.Method("POST")  res, err := req.Send()  if err != nil {    fmt.Printf("Request error: %s\n", err)    return  }  if !res.Ok {    fmt.Printf("Invalid server response: %d\n", res.StatusCode)    return  }  fmt.Printf("Status: %d\n", res.StatusCode)  fmt.Printf("Body: %s", res.String())}
import "gopkg.in/h2non/gentleman.v2/plugins/body"
clireqUse()cli.Use()clireq.Use()req.Use(body.JSON(data))body.JSON()dataContent-Type/Content-Lengthreq.Method("POST")http://httpbin.org/post
Status: 200Body: {  "args": {},   "data": "{\"foo\":\"bar\"}\n",   "files": {},   "form": {},   "headers": {    "Accept-Encoding": "gzip",     "Content-Length": "14",     "Content-Type": "application/json",     "Host": "httpbin.org",     "User-Agent": "gentleman/2.0.4",     "X-Amzn-Trace-Id": "Root=1-5e8dd0c7-ab423c10fb530deade846500"  },   "json": {    "foo": "bar"  },   "origin": "124.77.254.163",   "url": "http://httpbin.org/post"}

发送 XML 格式与上面的非常类似:

type User struct {  Name string `xml:"name"`  Age  int    `xml:"age"`}func main() {  cli := gentleman.New()  cli.URL("http://httpbin.org/post")  req := cli.Request()  req.Method("POST")  u := User{Name: "dj", Age: 18}  req.Use(body.XML(u))  // ...}

后半部分一样的代码我就省略了,运行结果:

Status: 200Body: {  "args": {},   "data": "<User><name>dj</name><age>18</age></User>",   "files": {},   "form": {},   "headers": {    "Accept-Encoding": "gzip",     "Content-Length": "41",     "Content-Type": "application/xml",     "Host": "httpbin.org",     "User-Agent": "gentleman/2.0.4",     "X-Amzn-Trace-Id": "Root=1-5e8dd339-830dba04536ceef247156746"  },   "json": null,   "origin": "222.64.16.70",   "url": "http://httpbin.org/post"}
header
headerUser-Agentheadercli
package mainimport (  "fmt"  "gopkg.in/h2non/gentleman.v2"  "gopkg.in/h2non/gentleman.v2/plugins/headers")func main() {  cli := gentleman.New()  cli.URL("https://api.thecatapi.com")  cli.Use(headers.Set("x-api-key", "479ce48d-db30-46a4-b1a0-91ac4c1477b8"))  cli.Use(headers.Del("User-Agent"))  req := cli.Request()  req.Path("/v1/breeds")  res, err := req.Send()  if err != nil {    fmt.Printf("Request error: %s\n", err)    return  }  if !res.Ok {    fmt.Printf("Invalid server response: %d\n", res.StatusCode)    return  }  fmt.Printf("Status: %d\n", res.StatusCode)  fmt.Printf("Body: %s", res.String())}
https://api.thecatapi.com479ce48d-db30-46a4-b1a0-91ac4c1477b8thecatapix-api-key
headerscligentlemanUser-AgentgentlemanUser-Agent: gentleman/2.0.4header.Del()

输出内容太多,我这里就不贴了。

query
?query stringgentlemanquerypagelimit
package mainimport (  "fmt"  "gopkg.in/h2non/gentleman.v2"  "gopkg.in/h2non/gentleman.v2/plugins/headers"  "gopkg.in/h2non/gentleman.v2/plugins/query")func main() {  cli := gentleman.New()  cli.URL("https://api.thecatapi.com")  cli.Use(headers.Set("x-api-key", "479ce48d-db30-46a4-b1a0-91ac4c1477b8"))  cli.Use(query.Set("attach_breed", "beng"))  cli.Use(query.Set("limit", "2"))  cli.Use(headers.Del("User-Agent"))  req := cli.Request()  req.Path("/v1/breeds")  req.Use(query.Set("page", "1"))  res, err := req.Send()  if err != nil {    fmt.Printf("Request error: %s\n", err)    return  }  if !res.Ok {    fmt.Printf("Invalid server response: %d\n", res.StatusCode)    return  }  fmt.Printf("Status: %d\n", res.StatusCode)  fmt.Printf("Body: %s", res.String())}
cli
cli.Use(query.Set("attach_breed", "beng"))cli.Use(query.Set("limit", "2"))
req
req.Use(query.Set("page", "1"))
query stringquery.Del()
url
/info/user/1/info/book/1/info/:class/1userbookgentlemanurl
package mainimport (  "fmt"  "os"  "gopkg.in/h2non/gentleman.v2"  "gopkg.in/h2non/gentleman.v2/plugins/headers"  "gopkg.in/h2non/gentleman.v2/plugins/url")func main() {  cli := gentleman.New()  cli.URL("https://api.thecatapi.com/")  cli.Use(headers.Set("x-api-key", "479ce48d-db30-46a4-b1a0-91ac4c1477b8"))  cli.Use(url.Path("/v1/:type"))  for _, arg := range os.Args[1:] {    req := cli.Request()    req.Use(url.Param("type", arg))    res, err := req.Send()    if err != nil {      fmt.Printf("Request error: %s\n", err)      return    }    if !res.Ok {      fmt.Printf("Invalid server response: %d\n", res.StatusCode)      return    }    fmt.Printf("Status: %d\n", res.StatusCode)    fmt.Printf("Body: %s\n", res.String())  }}
thecatapi/v1/breeds/v1/votes/v1/categoriesurlcliurl.Path("/v1/:type")url.Param("type", arg)type
$ go run main.go breeds votes categories

其他

gentlemanauthcookiescompressionproxyredirecttimeoutretryconsul

自定义

如果内置的和第三方的插件都不能满足我们的需求,我们还可以自定义插件。自定义的插件需要实现下面的接口:

// src/gopkg.in/h2non/gentleman.v2/plugin/plugin.gotype Plugin interface {  Enable()  Disable()  Disabled() bool  Remove()  Removed() bool  Exec(string, *context.Context, context.Handler)}
Exec()
PlugingentlemanLayerNewRequestPlugin/NewResponsePlugin/NewErrorPlugin

我们现在来实现一个插件,在请求之前输出一行信息,收到响应之后输出一行信息:

package mainimport (  "fmt"  "gopkg.in/h2non/gentleman.v2"  c "gopkg.in/h2non/gentleman.v2/context"  "gopkg.in/h2non/gentleman.v2/plugin")func main() {  cli := gentleman.New()  cli.URL("https://httpbin.org")  cli.Use(plugin.NewRequestPlugin(func(ctx *c.Context, h c.Handler) {    fmt.Println("request")    h.Next(ctx)  }))  cli.Use(plugin.NewResponsePlugin(func(ctx *c.Context, h c.Handler) {    fmt.Println("response")    h.Next(ctx)  }))  req := cli.Request()  req.Path("/headers")  res, err := req.Send()  if err != nil {    fmt.Printf("Request error: %s\n", err)    return  }  if !res.Ok {    fmt.Printf("Invalid server response: %d\n", res.StatusCode)    return  }  fmt.Printf("Status: %d\n", res.StatusCode)  fmt.Printf("Body: %s", res.String())}
NewRequestPlugin/NewResponsePluginfunc(ctx *c.Context, h c.Handler)ctxRequestResponse

总结

gentleman

大家如果发现好玩、好用的 Go 语言库,欢迎到 Go 每日一库 GitHub 上提交 issue????

参考


-

欢迎关注我的微信公众号【GoUpUp】,共同学习,一起进步~