深入浅出golangGolang 入门资料+笔记Go

Golang 中 Post & Get 请求

2017-10-14  本文已影响372人  HughFace

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

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

三方库: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()
上一篇 下一篇

猜你喜欢

热点阅读