对golang POST请求的封装

对golang POST请求的封装

写在前面

记录一下对golang自带的net/httpPOST请求的封装。此处使用的常规表单模拟的方法,可以传入文件与表单项,使用上更方便一些。这里仅提供一个思路及表单构造的一些方法,更多的使用说明应该参考官方文档。当然,你也可以修改为更适合你自己的方法。

注意: 此处并没有提供上下文的支持,如果需要,应当自行修改。

入口方法

构造一个POST请求,传入一些构造请求的参数,返回一个指向postRequest的指针。

1
func NewPost(c *PostRequestInputConfig) (*postRequest, error)
  • postRequest
1
2
3
4
5
6
7
8
9
10
11
type postRequest struct {
client *http.Client
req *http.Request
resp http.Response
}

func (r *postRequest) SetHeader(name, value string)

func (r *postRequest) AddHeader(name, value string)

func (r *postRequest) Send() (*http.Response, error)
  • PostRequestInputConfig
1
2
3
4
5
6
7
8
9
10
11
type PostRequestInputConfig struct {
Url string
Proxy string
Client *http.Client
Body *PostRequestBodyField
}

type PostRequestBodyField struct {
file map[string]string
field map[string]string
}
  1. Url: 请求的地址
  2. Proxy:使用代理,不使用留空即可
  3. Client:自定义client
  4. Body:表单内容,为PostRequestBodyField类型。使用两个map类型,无值请留空

使用参考

详见github

一个栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
post, err := NewPost(&PostRequestInputConfig{
Url: "https://sm.ms/api/v2/upload",
//Proxy: "socks5://127.0.0.1:1080",
//Client: nil,//自定义client,不使用无需设置此项
Body: &PostRequestBodyField{
file: map[string]string{"smfile": info.filePath},//文件 key 与文件路径
field: map[string]string{"format": "json"},//表单 key 与 value
},
})

post.SetHeader("Authorization", "token*************")

resp, err := post.Send()
defer resp.Body.Close()

完整代码

github or 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
* Copyright (c) 2020. sevth <sevthdev@gmail.com>
* Project name: Tool, File name: http_Post.go
* Date: 2020/5/6 下午1:03
* Author: sevth
*/
package golang

import (
"bytes"
"errors"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
)

type postRequest struct {
client *http.Client
req *http.Request
resp http.Response
}

type PostRequestInputConfig struct {
Url string
Proxy string
Client *http.Client
Body *PostRequestBodyField
}
type PostRequestBodyField struct {
file map[string]string
field map[string]string
}

func NewPost(c *PostRequestInputConfig) (*postRequest, error) {
var err error
r := &postRequest{}
// 检测url情况
if c.Url == "" {
return nil, errors.New("url is not set")
}

if c.Proxy != "" {
r.client = &http.Client{Transport: &http.Transport{
Proxy: func(_ *http.Request) (*url.URL, error) {
return url.Parse(c.Proxy)
},
}}
}
// 自定义client权重更高,设置了client的话,再设置proxy无效
if r.client == nil {
r.client = &http.Client{}
}
if c.Client != nil {
r.client = c.Client
}

body := &bytes.Buffer{}
bw := multipart.NewWriter(body)

for keyName, fp := range c.Body.file {
fw, err := bw.CreateFormFile(keyName, fp)
if err != nil {
return nil, err
//fmt.Println(err)
}
fd, err := os.Open(fp)
if err != nil {
return nil, err
//fmt.Println(err)
}
_, err = io.Copy(fw, fd)
fd.Close()
}

for k, v := range c.Body.field {
err := bw.WriteField(k, v)
if err != nil {
return nil, err
//fmt.Println(err)
}
}
_ = bw.Close() // 写完数据直接关闭,不然数据长度校验会出错

r.req, err = http.NewRequest("POST", c.Url, body)
if err != nil {
return nil, err
}
r.req.Header.Set("Content-Type", bw.FormDataContentType())
return r, nil
}

func (r *postRequest) SetHeader(name, value string) {
r.req.Header.Set(name, value)
}

func (r *postRequest) AddHeader(name, value string) {
r.req.Header.Add(name, value)
}

func (r *postRequest) Send() (*http.Response, error) {
resp, err := r.client.Do(r.req)
if err != nil {
return nil, err
}
return resp, nil
}

评论


:D 一言句子获取中...