主要记录一下使用过程中碰到的问题。
注意事项
请求一定需要记住关闭 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.当然如果返回错误是会自动关闭的
如果使用 NewRequest 来进行 POST 的表单提交,记得设置头部:
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
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()
普通使用
首先记录一下最简单的请求方式:
// GethttpClient := &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()// PosthttpClient := &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 := truedelimiter := '.'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()
作者:HughFace
链接:https://www.jianshu.com/p/2d429f6efbfc