Golang 中 Post & Get 请求

作者: HughFace | 来源:发表于2017-10-14 18:48 被阅读372次

    主要记录一下使用过程中碰到的问题。

    主要参考:网络请求 & 超时设置

    三方库:form & 自己的 fork

    注意事项

    1. 请求一定需要记住关闭 Body,否则容易造成资源无法重用导致堵死,源码如下。并且,Get, Post, or PostForm 都是使用了 client.Do 这个方法,因此都需要手动关闭

      package http
      type Client
      func Do:
      // If the returned error is nil, the Response will contain a non-nil
      // Body which the user is expected to close. If the Body is not
      // closed, the Client's underlying RoundTripper (typically Transport)
      // may not be able to re-use a persistent TCP connection to the server
      // for a subsequent "keep-alive" request.
      
      当然如果返回错误是会自动关闭的
      
    2. 如果使用 NewRequest 来进行 POST 的表单提交,记得设置头部:

      req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

    3. DefaultClient 中默认不会设置超时时间,普通使用没问题,但是如果在服务端生产环境比较容易导致问题 吐嘈文 比较难搞的是所有的封装好的函数,包括:http.Post http.Get 之类的,都使用的是 DefaultClient 。因此最好是平时使用的时候也设置一个超时时间

      httpClient := &http.Client{
       Timeout: 10 * time.Second,
      }
      res, err := httpClient.Get("some url")
      if err != nil {
       logs.Warn("something wrong here: %s", err.Error())
       return
      }
      defer res.Body.Close()
      

    普通使用

    首先记录一下最简单的请求方式:

    // Get
    httpClient := &http.Client{
        Timeout: 10 * time.Second,
    }
    res, err := httpClient.Get("some url")
    if err != nil {
        logs.Warn("something wrong here: %s", err.Error())
        return
    }
    defer res.Body.Close()
    
    // Post
    httpClient := &http.Client{
        Timeout: 10 * time.Second,
    }
    res, err := httpClient.Post("some url", "", nil)
    if err != nil {
        logs.Warn("something wrong here: %s", err.Error())
        return
    }
    defer res.Body.Close()
    

    数据提交时的处理

    主要是记录 Post 提交的时候,构造一个表单数据,同时增加几个头部字段。

    使用到了三方库:my form fork from form 主要是修改了空值处理还有标记处理:PR

    Tag 处理:

    原库默认使用 form 做标记,需要这样定义模型: 
    type PostData struct {
      Data1  string `form:"data1" json:"data1"`
      Data2 string `json:"data2"`
    }
    默认不会去解析 json 标记,所以 data2 不会包括在请求参数中。Po 主稍微改了一下,默认先检测 form,没有则去检测 json 标记,方便不想写两个重复的 tag 的情况:
    type PostData struct {
      Data1 string `form:"data1" json:"data1"`
      Data2 string `json:"data2"`
      Data3 string `json:"-"`
    }
    Po 主的库对于这种情况解析出来的数据参数有 data1 & data2,原库解析出来的数据有 data1 
    见仁见智吧,我还是不想写重复的标记
    

    空值处理:原库默认不包含空值

    原库对 `空值` 的处理如下:(空值包括 false & 0)
    foo := map[string]interface{}{"b": false, "i": 0}
    form.EncodeToString(foo)
    得到的结果是这样:
    "b=&i="
    默认不包括空值,只有设置了空值操作之后才行:
    keepZeros := true
    delimiter := '.'
    escape := '\\'
    form.EncodeToStringWith(foo, delimiter, escape, keepZeros)
    得到的结果是这样:
    "b=false&i=0"
    

    空值处理:默认直接包含空值,正好和原库相反

    Po 主库对 `空值` 的处理如下:(空值包括 false & 0)
    foo := map[string]interface{}{"b": false, "i": 0}
    form.EncodeToString(foo)
    得到的结果是这样:
    "b=false&i=0"
    默认包括空值,设置了空值操作之后:
    form.EncodeToStringWith(foo, true)
    得到的结果是这样:
    "b=&i="
    

    Post form 的使用样例

    httpClient := &http.Client{
        Timeout: 10 * time.Second,
    }
    data := map[string]interface{}{"b": false, "i": 0}
    formData, err := form.EncodeToString(data)
    if err != nil {
        return
    }
    req, err := httpClient.NewRequest("POST", "some url", strings.NewReader(formData))
    if err != nil {
        return
    }
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded;charset=utf-8;")
    res, err := client.Do(req)
    if err != nil {
        return
    }
    defer res.Body.Close()
    

    相关文章

      网友评论

        本文标题:Golang 中 Post & Get 请求

        本文链接:https://www.haomeiwen.com/subject/qfcfuxtx.html