• HTTP客户端
    • ghttp.Client
      • 工具方法
      • 一些重要说明
      • 数组及复杂类型参数
    • ghttp.ClientResponse
    • 基本示例
    • 文件上传
    • 自定义Header

    HTTP客户端

    ghttp.Client

    gf框架提供了强大易用的HTTP客户端,同样由ghttp模块实现。

    方法列表:https://godoc.org/github.com/gogf/gf/g/net/ghttp#Client

    1. type Client
    2. func NewClient() *Client
    3. func (c *Client) Get(url string) (*ClientResponse, error)
    4. func (c *Client) Put(url string, data ...interface{}) (*ClientResponse, error)
    5. func (c *Client) Post(url string, data ...interface{}) (*ClientResponse, error)
    6. func (c *Client) Delete(url string, data ...interface{}) (*ClientResponse, error)
    7. func (c *Client) Connect(url string, data ...interface{}) (*ClientResponse, error)
    8. func (c *Client) Head(url string, data ...interface{}) (*ClientResponse, error)
    9. func (c *Client) Options(url string, data ...interface{}) (*ClientResponse, error)
    10. func (c *Client) Patch(url string, data ...interface{}) (*ClientResponse, error)
    11. func (c *Client) Trace(url string, data ...interface{}) (*ClientResponse, error)
    12. func (c *Client) DoRequest(method, url string, data ...interface{}) (*ClientResponse, error)
    13. func (c *Client) GetContent(url string, data ...interface{}) string
    14. func (c *Client) PutContent(url string, data ...interface{}) string
    15. func (c *Client) PostContent(url string, data ...interface{}) string
    16. func (c *Client) DeleteContent(url string, data ...interface{}) string
    17. func (c *Client) ConnectContent(url string, data ...interface{}) string
    18. func (c *Client) HeadContent(url string, data ...interface{}) string
    19. func (c *Client) OptionsContent(url string, data ...interface{}) string
    20. func (c *Client) PatchContent(url string, data ...interface{}) string
    21. func (c *Client) TraceContent(url string, data ...interface{}) string
    22. func (c *Client) DoRequestContent(method string, url string, data ...interface{}) string
    23. func (c *Client) SetBasicAuth(user, pass string)
    24. func (c *Client) SetBrowserMode(enabled bool)
    25. func (c *Client) SetCookie(key, value string)
    26. func (c *Client) SetCookieMap(cookieMap map[string]string)
    27. func (c *Client) SetHeader(key, value string)
    28. func (c *Client) SetHeaderRaw(header string)
    29. func (c *Client) SetPrefix(prefix string)
    30. func (c *Client) SetTimeOut(t time.Duration)

    简要说明:

    1. 我们可以使用NewClient创建一个自定义的HTTP客户端对象Client,随后可以使用该对象执行请求。
    2. 客户端提供了一系列以HTTP Method命名的方法,调用这些方法将会发起对应的HTTP Method请求。常用的方法当然是GetPost方法,同时DoRequest是核心的请求方法,用户可以调用该方法实现自定义的HTTP Method发送请求。
    3. 请求返回结果为*ClientResponse对象,可以通过该结果对象获取对应的返回结果,通过ReadAll方法可以获得返回的内容。以*Content命名的请求方法结果为字符串内容,如果请求失败时,得到的是空字符串。
    4. 可以看到,客户端的请求参数的数据参数data数据类型为interface{}类型,也就是说可以传递任意的数据类型,常见的参数数据类型为string/map,如果参数为map类型,参数值将会进行urlencode编码。

    工具方法

    ghttp模块也提供了独立的包函数来实现HTTP请求,函数列表如下:

    1. func Get(url string) (*ClientResponse, error)
    2. func Put(url string, data ...interface{}) (*ClientResponse, error)
    3. func Post(url string, data ...interface{}) (*ClientResponse, error)
    4. func Delete(url string, data ...interface{}) (*ClientResponse, error)
    5. func Head(url string, data ...interface{}) (*ClientResponse, error)
    6. func Patch(url string, data ...interface{}) (*ClientResponse, error)
    7. func Connect(url string, data ...interface{}) (*ClientResponse, error)
    8. func Options(url string, data ...interface{}) (*ClientResponse, error)
    9. func Trace(url string, data ...interface{}) (*ClientResponse, error)
    10. func DoRequest(method, url string, data ...interface{}) (*ClientResponse, error)
    11. func GetContent(url string, data ...interface{}) string
    12. func PutContent(url string, data ...interface{}) string
    13. func PostContent(url string, data ...interface{}) string
    14. func DeleteContent(url string, data ...interface{}) string
    15. func HeadContent(url string, data ...interface{}) string
    16. func PatchContent(url string, data ...interface{}) string
    17. func ConnectContent(url string, data ...interface{}) string
    18. func OptionsContent(url string, data ...interface{}) string
    19. func TraceContent(url string, data ...interface{}) string
    20. func RequestContent(method string, url string, data ...interface{}) string

    函数说明与Client对象的方法说明一致,一般情况下直接使用ghttp对应的HTTP包方法来实现HTTP请求即可,非常简便。当需要自定义HTTP请求的一些细节(例如超时时间、Cookie、Header等)时,就得依靠自定义的Client对象来处理了。

    一些重要说明

    1. ghttp客户端默认关闭了KeepAlive功能以及对服务端TLS证书的校验功能,如果需要启用可自定义客户端的Transport属性;
    2. Post/PostContent方法提交的请求类型(Content-Type)默认为application/x-www-form-urlencoded,当data参数为JSON类型时,将会被自动识别此时请求的类型为application/json

    数组及复杂类型参数

    数组参数可以通过例如array=1&array=2&array=3这样的方式传递,但是推荐复杂数据类型使用JSON数据格式传递。

    由于gf框架的WebServer基于net/http标准库,因此遵循标准库的参数设计方式,array=1&array=2&array=3这样的提交参数将会被解析为数组变量array,不支持array[]=1&array[]=2&array[]=3这样的数组提交方式,也不支持map[a]=1&map[b]=2&map[c]=3这样的map提交方式。

    ghttp.ClientResponse

    ClientResponse为HTTP对应请求的返回结果对象,该对象继承于http.Response,可以使用http.Response的所有方法。在此基础之上增加了以下两个方法:

    1. func (r *ClientResponse) GetCookie(key string) string
    2. func (r *ClientResponse) ReadAll() []byte
    3. func (r *ClientResponse) ReadAllString() string
    4. func (r *ClientResponse) Close()

    这里也要提醒的是,ClientResponse需要手动调用Close方法关闭,也就是说,不管你使用不使用返回的ClientResponse对象,你都需要将该返回对象赋值给一个变量,并且手动调用其Close方法进行关闭(往往使用defer r.Close())。需要手动关闭返回对象这一点,与标准库的HTTP客户端请求对象操作相同。

    基本示例

    我们来看几个HTTP客户端请求的例子:

    1. 发送GET请求,并打印出返回值

      1. if r, e := ghttp.Get("https://goframe.org"); e != nil {
      2. panic(e)
      3. } else {
      4. defer r.Close()
      5. fmt.Println(r.ReadAllString())
      6. }
    2. 发送GET请求,下载远程文件

      1. if r, e := ghttp.Get("https://goframe.org/cover.png"); e != nil {
      2. panic(e)
      3. } else {
      4. defer r.Close()
      5. gfile.PutBinContents("/Users/john/Temp/cover.png", r.ReadAll())
      6. }

      下载文件操作,小文件下载非常简单。需要注意的是,如果远程文件比较大时,服务端会分批返回数据,因此会需要客户端发多个GET请求,每一次通过Header来请求分批的文件范围长度,感兴趣的同学可自行研究相关细节。

    3. 发送POST请求,并打印出返回值

      1. if r, e := ghttp.Post("http://127.0.0.1:8199/form", "name=john&age=18"); e != nil {
      2. panic(e)
      3. } else {
      4. defer r.Close()
      5. fmt.Println(r.ReadAllString())
      6. }

      传递多参数的时候用户可以使用&符号进行连接。

    4. 发送POST请求,参数为map类型,并打印出返回值

      1. if r, e := ghttp.Post("http://127.0.0.1:8199/form", g.Map{
      2. "submit" : "1",
      3. "callback" : "http://127.0.0.1/callback?url=http://baidu.com",
      4. })); e != nil {
      5. panic(e)
      6. } else {
      7. defer r.Close()
      8. fmt.Println(r.ReadAllString())
      9. }

      传递多参数的时候用户可以使用&符号进行连接,也可以直接使用map(其实之前也提到,任意数据类型都支持,包括struct)。

    5. 发送POST请求,参数为JSON数据,并打印出返回值

      1. if r, e := ghttp.Post("http://127.0.0.1:8199/api/user", `{"passport":"john","password":"123456","password-confirm":"123456"}`); e != nil {
      2. panic(e)
      3. } else {
      4. defer r.Close()
      5. fmt.Println(r.ReadAllString())
      6. }

      可以看到,通过ghttp客户端发送JSON数据请求非常方便,直接通过Post方法提交即可,客户端会自动将请求的Content-Type设置为application/json

    6. 发送DELETE请求,并打印出返回值

      1. if r, e := ghttp.Delete("http://127.0.0.1:8199/user", "10000"); e != nil {
      2. panic(e)
      3. } else {
      4. defer r.Close()
      5. fmt.Println(r.ReadAllString())
      6. }

    文件上传

    gf的HTTP客户端封装并极大简化了文件上传功能,直接上例子:

    1. 客户端

      https://github.com/gogf/gf/blob/master/geg/net/ghttp/client/upload/client.go

      1. package main
      2. import (
      3. "fmt"
      4. "github.com/gogf/gf/g/os/glog"
      5. "github.com/gogf/gf/g/net/ghttp"
      6. )
      7. func main() {
      8. path := "/home/john/Workspace/Go/github.com/gogf/gf/version.go"
      9. r, e := ghttp.Post("http://127.0.0.1:8199/upload", "name=john&age=18&upload-file=@file:" + path)
      10. if e != nil {
      11. glog.Error(e)
      12. } else {
      13. fmt.Println(r.ReadAllString())
      14. r.Close()
      15. }
      16. }

      注意到了吗?文件上传参数格式使用了 参数名=@file:文件路径 ,HTTP客户端将会自动解析文件路径对应的文件内容并读取提交给服务端。原本复杂的文件上传操作被gf进行了封装处理,用户只需要使用 @file:+文件路径 来构成参数值即可。

      其中,文件路径请使用本地文件绝对路径。

    2. 服务端

      https://github.com/gogf/gf/blob/master/geg/net/ghttp/client/upload/server.go

      1. package main
      2. import (
      3. "github.com/gogf/gf/g"
      4. "github.com/gogf/gf/g/os/gfile"
      5. "github.com/gogf/gf/g/net/ghttp"
      6. )
      7. // 执行文件上传处理,上传到系统临时目录 /tmp
      8. func Upload(r *ghttp.Request) {
      9. if f, h, e := r.FormFile("upload-file"); e == nil {
      10. defer f.Close()
      11. name := gfile.Basename(h.Filename)
      12. buffer := make([]byte, h.Size)
      13. f.Read(buffer)
      14. gfile.PutBinContents("/tmp/" + name, buffer)
      15. r.Response.Write(name + " uploaded successly")
      16. } else {
      17. r.Response.Write(e.Error())
      18. }
      19. }
      20. // 展示文件上传页面
      21. func UploadShow(r *ghttp.Request) {
      22. r.Response.Write(`
      23. <html>
      24. <head>
      25. <title>上传文件</title>
      26. </head>
      27. <body>
      28. <form enctype="multipart/form-data" action="/upload" method="post">
      29. <input type="file" name="upload-file" />
      30. <input type="submit" value="upload" />
      31. </form>
      32. </body>
      33. </html>
      34. `)
      35. }
      36. func main() {
      37. s := g.Server()
      38. s.BindHandler("/upload", Upload)
      39. s.BindHandler("/upload/show", UploadShow)
      40. s.SetPort(8199)
      41. s.Run()
      42. }

      访问 http://127.0.0.1:8199/upload/show 选择需要上传的文件,提交之后可以看到文件上传成功到服务器上。

      文件上传比较简单,但是需要注意的是,服务端在上传处理中需要使用 f.Close() 关闭掉临时上传文件打开的指针

    自定义Header

    http客户端发起请求时可以自定义发送给服务端的Header内容,该特性使用SetHeader/SetHeaderRaw方法实现。我们来看一个客户端自定义Cookie的例子。

    1. 客户端

      https://github.com/gogf/gf/blob/master/geg/net/ghttp/client/cookie/client.go

      1. package main
      2. import (
      3. "fmt"
      4. "github.com/gogf/gf/g/net/ghttp"
      5. )
      6. func main() {
      7. c := ghttp.NewClient()
      8. c.SetHeader("Cookie", "name=john; score=100")
      9. if r, e := c.Get("http://127.0.0.1:8199/"); e != nil {
      10. panic(e)
      11. } else {
      12. fmt.Println(r.ReadAllString())
      13. }
      14. }

      通过ghttp.NewClient()创建一个自定义的http请求客户端对象,并通过c.SetHeader("Cookie", "name=john; score=100")设置自定义的Cookie,这里我们设置了两个示例用的Cookie参数,一个name,一个score,注意多个Cookie参数使用;符号分隔。

    2. 服务端

      https://github.com/gogf/gf/blob/master/geg/net/ghttp/client/cookie/server.go

      1. package main
      2. import (
      3. "github.com/gogf/gf/g"
      4. "github.com/gogf/gf/g/net/ghttp"
      5. )
      6. func main() {
      7. s := g.Server()
      8. s.BindHandler("/", func(r *ghttp.Request){
      9. r.Response.Writeln(r.Cookie.Map())
      10. })
      11. s.SetPort(8199)
      12. s.Run()
      13. }

      服务端的逻辑很简单,直接将接收到的Cookie参数全部打印出来。

    3. 执行结果

      客户端代码执行后,终端将会打印出服务端的返回结果,如下:

      1. map[name:john score:100]

      可以看到,服务端已经接收到了客户端自定义的Cookie参数。

    4. 使用SetHeaderRaw自定义Header

      这个方法十分强大,给个例子:

      1. c := ghttp.NewClient()
      2. c.SetHeaderRaw(`
      3. accept-encoding: gzip, deflate, br
      4. accept-language: zh-CN,zh;q=0.9,en;q=0.8
      5. referer: https://idonottell.you
      6. cookie: name=john
      7. user-agent: my test http client
      8. `)
      9. if r, e := c.Get("http://127.0.0.1:8199/"); e != nil {
      10. panic(e)
      11. } else {
      12. fmt.Println(r.ReadAllString())
      13. }

      Do you get it?