mirror of
https://github.com/silenceper/wechat.git
synced 2026-02-08 06:32:27 +08:00
Merge remote-tracking branch '官方/v2' into release-2.0
# Conflicts: # work/message/client.go # work/message/message.go # work/oauth/oauth.go # work/work.go
This commit is contained in:
@@ -6,7 +6,7 @@ import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// CommonError 微信返回的通用错误json
|
||||
// CommonError 微信返回的通用错误 json
|
||||
type CommonError struct {
|
||||
apiName string
|
||||
ErrCode int64 `json:"errcode"`
|
||||
@@ -17,7 +17,7 @@ func (c *CommonError) Error() string {
|
||||
return fmt.Sprintf("%s Error , errcode=%d , errmsg=%s", c.apiName, c.ErrCode, c.ErrMsg)
|
||||
}
|
||||
|
||||
// NewCommonError 新建CommonError错误,对于无errcode和errmsg的返回也可以返回该通用错误
|
||||
// NewCommonError 新建 CommonError 错误,对于无 errcode 和 errmsg 的返回也可以返回该通用错误
|
||||
func NewCommonError(apiName string, code int64, msg string) *CommonError {
|
||||
return &CommonError{
|
||||
apiName: apiName,
|
||||
@@ -26,7 +26,7 @@ func NewCommonError(apiName string, code int64, msg string) *CommonError {
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeWithCommonError 将返回值按照CommonError解析
|
||||
// DecodeWithCommonError 将返回值按照 CommonError 解析
|
||||
func DecodeWithCommonError(response []byte, apiName string) (err error) {
|
||||
var commError CommonError
|
||||
err = json.Unmarshal(response, &commError)
|
||||
|
||||
72
util/http.go
72
util/http.go
@@ -17,6 +17,19 @@ import (
|
||||
"golang.org/x/crypto/pkcs12"
|
||||
)
|
||||
|
||||
// URIModifier URI修改器
|
||||
type URIModifier func(uri string) string
|
||||
|
||||
var uriModifier URIModifier
|
||||
|
||||
// DefaultHTTPClient 默认httpClient
|
||||
var DefaultHTTPClient = http.DefaultClient
|
||||
|
||||
// SetURIModifier 设置URI修改器
|
||||
func SetURIModifier(fn URIModifier) {
|
||||
uriModifier = fn
|
||||
}
|
||||
|
||||
// HTTPGet get 请求
|
||||
func HTTPGet(uri string) ([]byte, error) {
|
||||
return HTTPGetContext(context.Background(), uri)
|
||||
@@ -24,11 +37,14 @@ func HTTPGet(uri string) ([]byte, error) {
|
||||
|
||||
// HTTPGetContext get 请求
|
||||
func HTTPGetContext(ctx context.Context, uri string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
response, err := DefaultHTTPClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -47,6 +63,9 @@ func HTTPPost(uri string, data string) ([]byte, error) {
|
||||
|
||||
// HTTPPostContext post 请求
|
||||
func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[string]string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
body := bytes.NewBuffer(data)
|
||||
request, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, body)
|
||||
if err != nil {
|
||||
@@ -57,7 +76,7 @@ func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[st
|
||||
request.Header.Set(key, value)
|
||||
}
|
||||
|
||||
response, err := http.DefaultClient.Do(request)
|
||||
response, err := DefaultHTTPClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -69,8 +88,11 @@ func HTTPPostContext(ctx context.Context, uri string, data []byte, header map[st
|
||||
return io.ReadAll(response.Body)
|
||||
}
|
||||
|
||||
// PostJSON post json 数据请求
|
||||
func PostJSON(uri string, obj interface{}) ([]byte, error) {
|
||||
// PostJSONContext post json 数据请求
|
||||
func PostJSONContext(ctx context.Context, uri string, obj interface{}) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
jsonBuf := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(jsonBuf)
|
||||
enc.SetEscapeHTML(false)
|
||||
@@ -78,7 +100,12 @@ func PostJSON(uri string, obj interface{}) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response, err := http.Post(uri, "application/json;charset=utf-8", jsonBuf)
|
||||
req, err := http.NewRequestWithContext(ctx, "POST", uri, jsonBuf)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json;charset=utf-8")
|
||||
response, err := DefaultHTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -90,7 +117,12 @@ func PostJSON(uri string, obj interface{}) ([]byte, error) {
|
||||
return io.ReadAll(response.Body)
|
||||
}
|
||||
|
||||
// PostJSONWithRespContentType post json数据请求,且返回数据类型
|
||||
// PostJSON post json 数据请求
|
||||
func PostJSON(uri string, obj interface{}) ([]byte, error) {
|
||||
return PostJSONContext(context.Background(), uri, obj)
|
||||
}
|
||||
|
||||
// PostJSONWithRespContentType post json 数据请求,且返回数据类型
|
||||
func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, error) {
|
||||
jsonBuf := new(bytes.Buffer)
|
||||
enc := json.NewEncoder(jsonBuf)
|
||||
@@ -100,7 +132,7 @@ func PostJSONWithRespContentType(uri string, obj interface{}) ([]byte, string, e
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
response, err := http.Post(uri, "application/json;charset=utf-8", jsonBuf)
|
||||
response, err := DefaultHTTPClient.Post(uri, "application/json;charset=utf-8", jsonBuf)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -136,6 +168,9 @@ type MultipartFormField struct {
|
||||
|
||||
// PostMultipartForm 上传文件或其他多个字段
|
||||
func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte, err error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
bodyBuf := &bytes.Buffer{}
|
||||
bodyWriter := multipart.NewWriter(bodyBuf)
|
||||
|
||||
@@ -173,7 +208,7 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
|
||||
contentType := bodyWriter.FormDataContentType()
|
||||
bodyWriter.Close()
|
||||
|
||||
resp, e := http.Post(uri, contentType, bodyBuf)
|
||||
resp, e := DefaultHTTPClient.Post(uri, contentType, bodyBuf)
|
||||
if e != nil {
|
||||
err = e
|
||||
return
|
||||
@@ -188,13 +223,16 @@ func PostMultipartForm(fields []MultipartFormField, uri string) (respBody []byte
|
||||
|
||||
// PostXML perform a HTTP/POST request with XML body
|
||||
func PostXML(uri string, obj interface{}) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
xmlData, err := xml.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
body := bytes.NewBuffer(xmlData)
|
||||
response, err := http.Post(uri, "application/xml;charset=utf-8", body)
|
||||
response, err := DefaultHTTPClient.Post(uri, "application/xml;charset=utf-8", body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -206,7 +244,7 @@ func PostXML(uri string, obj interface{}) ([]byte, error) {
|
||||
return io.ReadAll(response.Body)
|
||||
}
|
||||
|
||||
// httpWithTLS CA证书
|
||||
// httpWithTLS CA 证书
|
||||
func httpWithTLS(rootCa, key string) (*http.Client, error) {
|
||||
var client *http.Client
|
||||
certData, err := os.ReadFile(rootCa)
|
||||
@@ -217,15 +255,14 @@ func httpWithTLS(rootCa, key string) (*http.Client, error) {
|
||||
config := &tls.Config{
|
||||
Certificates: []tls.Certificate{cert},
|
||||
}
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: config,
|
||||
DisableCompression: true,
|
||||
}
|
||||
client = &http.Client{Transport: tr}
|
||||
trans := (DefaultHTTPClient.Transport.(*http.Transport)).Clone()
|
||||
trans.TLSClientConfig = config
|
||||
trans.DisableCompression = true
|
||||
client = &http.Client{Transport: trans}
|
||||
return client, nil
|
||||
}
|
||||
|
||||
// pkcs12ToPem 将Pkcs12转成Pem
|
||||
// pkcs12ToPem 将 Pkcs12 转成 Pem
|
||||
func pkcs12ToPem(p12 []byte, password string) tls.Certificate {
|
||||
blocks, err := pkcs12.ToPEM(p12, password)
|
||||
defer func() {
|
||||
@@ -249,6 +286,9 @@ func pkcs12ToPem(p12 []byte, password string) tls.Certificate {
|
||||
|
||||
// PostXMLWithTLS perform a HTTP/POST request with XML body and TLS
|
||||
func PostXMLWithTLS(uri string, obj interface{}, ca, key string) ([]byte, error) {
|
||||
if uriModifier != nil {
|
||||
uri = uriModifier(uri)
|
||||
}
|
||||
xmlData, err := xml.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
24
util/query.go
Normal file
24
util/query.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Query 将Map序列化为Query参数
|
||||
func Query(params map[string]interface{}) string {
|
||||
finalString := make([]string, 0)
|
||||
for key, value := range params {
|
||||
valueString := ""
|
||||
switch v := value.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
valueString = fmt.Sprintf("%d", v)
|
||||
case bool:
|
||||
valueString = fmt.Sprintf("%v", v)
|
||||
default:
|
||||
valueString = fmt.Sprintf("%s", v)
|
||||
}
|
||||
finalString = append(finalString, strings.Join([]string{key, valueString}, "="))
|
||||
}
|
||||
return strings.Join(finalString, "&")
|
||||
}
|
||||
19
util/query_test.go
Normal file
19
util/query_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestQuery query method test case
|
||||
func TestQuery(t *testing.T) {
|
||||
result := Query(map[string]interface{}{
|
||||
"age": 12,
|
||||
"name": "Alan",
|
||||
"cat": "Peter",
|
||||
})
|
||||
if result == "" {
|
||||
// 由于hash是乱序 所以没法很好的预测输出的字符串
|
||||
// 将会输出符合Query规则的字符串 "age=12&name=Alan&cat=Peter"
|
||||
t.Error("NOT PASS")
|
||||
}
|
||||
}
|
||||
24
util/template.go
Normal file
24
util/template.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Template 对字符串中的和map的key相同的字符串进行模板替换 仅支持 形如: {name}
|
||||
func Template(source string, data map[string]interface{}) string {
|
||||
sourceCopy := &source
|
||||
for k, val := range data {
|
||||
valStr := ""
|
||||
switch v := val.(type) {
|
||||
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
|
||||
valStr = fmt.Sprintf("%d", v)
|
||||
case bool:
|
||||
valStr = fmt.Sprintf("%v", v)
|
||||
default:
|
||||
valStr = fmt.Sprintf("%s", v)
|
||||
}
|
||||
*sourceCopy = strings.Replace(*sourceCopy, strings.Join([]string{"{", k, "}"}, ""), valStr, 1)
|
||||
}
|
||||
return *sourceCopy
|
||||
}
|
||||
20
util/template_test.go
Normal file
20
util/template_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestTemplate testing case about Template method
|
||||
func TestTemplate(t *testing.T) {
|
||||
result := Template("{name}={age};{with}={another};any={any};boolean={boolean}", map[string]interface{}{
|
||||
"name": "Helan",
|
||||
"age": "33",
|
||||
"with": "Pep",
|
||||
"another": "C",
|
||||
"any": 33,
|
||||
"boolean": false,
|
||||
})
|
||||
if result != "Helan=33;Pep=C;any=33;boolean=false" {
|
||||
t.Error("NOT PSS testing")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user