forked from royalrick/weapp
/
util.go
158 lines (131 loc) · 3.4 KB
/
util.go
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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package util
import (
"bytes"
"crypto/tls"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"math/rand"
"net"
"net/http"
"net/url"
"time"
)
// TokenAPI 获取带 token 的 API 地址
func TokenAPI(api, token string) (string, error) {
u, err := url.Parse(api)
if err != nil {
return "", err
}
query := u.Query()
query.Set("access_token", token)
u.RawQuery = query.Encode()
return u.String(), nil
}
// GetQuery returns url query value
func GetQuery(req *http.Request, key string) string {
if values, ok := req.URL.Query()[key]; ok && len(values) > 0 {
return values[0]
}
return ""
}
// RandomString random string generator
//
// @ln length of return string
func RandomString(ln int) string {
letters := []rune("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
b := make([]rune, ln)
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := range b {
b[i] = letters[r.Intn(len(letters))]
}
return string(b)
}
// PostXML perform a HTTP/POST request with XML body
func PostXML(uri string, obj interface{}) ([]byte, error) {
data, err := xml.Marshal(obj)
if err != nil {
return nil, err
}
body := bytes.NewBuffer(data)
res, err := http.Post(uri, "application/xml; charset=utf-8", body)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http code error : uri=%v , statusCode=%v", uri, res.StatusCode)
}
return ioutil.ReadAll(res.Body)
}
// TSLPostXML ...
func TSLPostXML(uri string, obj interface{}, certPath, keyPath string) ([]byte, error) {
data, err := xml.Marshal(obj)
if err != nil {
return nil, err
}
body := bytes.NewBuffer(data)
cli, err := NewTLSClient(certPath, keyPath)
if err != nil {
return nil, err
}
res, err := cli.Post(uri, "application/xml; charset=utf-8", body)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http code error : uri=%v , statusCode=%v", uri, res.StatusCode)
}
return ioutil.ReadAll(res.Body)
}
// NewTLSClient 创建支持双向证书认证的 http.Client.
func NewTLSClient(certPath, keyPath string) (httpClient *http.Client, err error) {
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, err
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
return newTLSClient(tlsConfig)
}
func newTLSClient(tlsConfig *tls.Config) (*http.Client, error) {
dialTLS := func(network, addr string) (net.Conn, error) {
return tls.DialWithDialer(&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}, network, addr, tlsConfig)
}
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
DialTLS: dialTLS,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
},
}, nil
}
// FetchIP current IP address
func FetchIP() (net.IP, error) {
addrs, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
for index := range addrs {
// 检查ip地址判断是否回环地址
if IPNet, ok := addrs[index].(*net.IPNet); ok && !IPNet.IP.IsLoopback() {
if IPNet.IP.To4() != nil {
return IPNet.IP, nil
}
}
}
return nil, errors.New("failed to found IP address")
}