This commit is contained in:
tanghc
2020-06-17 10:36:22 +08:00
parent f66e2f8891
commit 6406f023db
41 changed files with 1195 additions and 2 deletions

View File

@@ -0,0 +1,126 @@
package common
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"mime/multipart"
"net/http"
"net/url"
"os"
"path/filepath"
"strings"
)
type UploadFile struct {
// 表单名称
Name string
Filepath string
}
// 请求客户端
var httpClient = &http.Client{}
func Get(reqUrl string, allParams map[string]string, headers map[string]string) string {
urlParams := url.Values{}
Url, _ := url.Parse(reqUrl)
for key, val := range allParams {
urlParams.Set(key, val)
}
//如果参数中有中文参数,这个方法会进行URLEncode
Url.RawQuery = urlParams.Encode()
// 得到完整的urlhttp://xx?query
urlPath := Url.String()
httpRequest,_ := http.NewRequest("GET", urlPath, nil)
// 添加请求头
if headers != nil {
for k, v := range headers {
httpRequest.Header.Add(k,v)
}
}
// 发送请求
resp, err := httpClient.Do(httpRequest)
if err != nil {
panic(err)
}
defer resp.Body.Close()
response, _ := ioutil.ReadAll(resp.Body)
return string(response)
}
func PostForm(reqUrl string, allParams map[string]string, headers map[string]string) string {
return post(reqUrl, allParams, "application/x-www-form-urlencoded", nil, headers)
}
func PostJson(reqUrl string, allParams map[string]string, headers map[string]string) string {
return post(reqUrl, allParams, "application/json", nil, headers)
}
func PostFile(reqUrl string, allParams map[string]string, files []UploadFile, headers map[string]string) string {
return post(reqUrl, allParams, "multipart/form-data", files, headers)
}
func post(reqUrl string, allParams map[string]string, contentType string, files []UploadFile, headers map[string]string) string {
requestBody, realContentType := getReader(allParams, contentType, files)
httpRequest,_ := http.NewRequest("POST", reqUrl, requestBody)
// 添加请求头
httpRequest.Header.Add("Content-Type", realContentType)
if headers != nil {
for k, v := range headers {
httpRequest.Header.Add(k,v)
}
}
// 发送请求
resp, err := httpClient.Do(httpRequest)
if err != nil {
panic(err)
}
defer resp.Body.Close()
response, _ := ioutil.ReadAll(resp.Body)
return string(response)
}
func getReader(allParams map[string]string, contentType string, files []UploadFile) (io.Reader, string) {
if strings.Index(contentType, "json") > -1 {
bytesData, _ := json.Marshal(allParams)
return bytes.NewReader(bytesData), contentType
} else if files != nil {
body := &bytes.Buffer{}
// 文件写入 body
writer := multipart.NewWriter(body)
for _, uploadFile := range files {
file, err := os.Open(uploadFile.Filepath)
if err != nil {
panic(err)
}
part, err := writer.CreateFormFile(uploadFile.Name, filepath.Base(uploadFile.Filepath))
if err != nil {
panic(err)
}
_, err = io.Copy(part, file)
file.Close()
}
// 其他参数列表写入 body
for k, v := range allParams {
if err := writer.WriteField(k, v); err != nil {
panic(err)
}
}
if err := writer.Close(); err != nil {
panic(err)
}
// 上传文件需要自己专用的contentType
return body, writer.FormDataContentType()
} else {
urlValues := url.Values{}
for key, val := range allParams {
urlValues.Set(key, val)
}
reqBody:= urlValues.Encode()
return strings.NewReader(reqBody), contentType
}
}

View File

@@ -0,0 +1,24 @@
package common
type RequestType string
const (
GET RequestType = "GET"
POST_JSON RequestType = "POST_JSON"
POST_FORM RequestType = "POST_FORM"
POST_UPLOAD RequestType = "POST_UPLOAD"
)
type Model struct {
// 业务参数
BizModel interface{}
// 上传文件
Files []UploadFile
}
type IRequest interface {
GetMethod() string
GetVersion() string
GetRequestType() RequestType
GetModel() Model
}

View File

@@ -0,0 +1,108 @@
package common
import (
"encoding/json"
"errors"
"reflect"
"strings"
"time"
)
var headers = map[string]string{
"Accept-Encoding": "identity",
}
type IClient interface {
Execute() string
}
type OpenClient struct {
AppId string
PrivateKey string
Url string
}
func (client OpenClient) ExecuteToken(iRequest IRequest, token string) []byte {
model := iRequest.GetModel()
bizModel := model.BizModel
types := reflect.TypeOf(bizModel)
values := reflect.ValueOf(bizModel)
params := make(map[string]interface{})
//遍历结构体的所有字段
for i := 0; i < values.NumField(); i++ {
// 获取到struct标签需要通过reflect.Type来获取tag标签的值
fieldName := types.Field(i).Tag.Get("json")
// 如果该字段有tag标签就显示否则就不显示
if fieldName != "" {
params[fieldName] = values.Field(i).Interface()
}
}
requestType := iRequest.GetRequestType()
var response string
allParams := client.buildParams(iRequest, params, token)
if model.Files != nil && len(model.Files) > 0 {
response = PostFile(client.Url, allParams, model.Files, headers)
} else {
switch requestType {
case GET:
response = Get(client.Url, allParams, headers)
case POST_FORM:
response = PostForm(client.Url, allParams, headers)
case POST_JSON:
response = PostJson(client.Url, allParams, headers)
case POST_UPLOAD:
response = PostFile(client.Url, allParams, model.Files, headers)
default:
panic(errors.New("GetRequestType()返回错误"))
}
}
return parseResponseResult(iRequest, response)
}
func parseResponseResult(iRequest IRequest, response string) []byte {
var responseRoot = map[string]interface{}{}
var err = json.Unmarshal([]byte(response), &responseRoot)
if err != nil {
panic(err)
}
requestId := responseRoot["request_id"].(string)
var responseDataMap = responseRoot["error_response"]
if responseDataMap == nil {
dataName := strings.ReplaceAll(iRequest.GetMethod(), ".", "_") + "_response"
responseDataMap = responseRoot[dataName]
}
responseDataMap.(map[string]interface{})["request_id"] = requestId
// json数据
dataJsonBytes, _ := json.Marshal(responseDataMap)
return dataJsonBytes
}
func (client OpenClient) buildParams(iRequest IRequest, params map[string]interface{}, token string) map[string]string {
allParams := map[string]string{
"app_id": client.AppId,
"method": iRequest.GetMethod(),
"charset": "UTF-8",
"sign_type": "RSA2",
"timestamp": time.Now().Format("2006-01-02 15:04:05"),
"version": iRequest.GetVersion(),
}
if token != "" {
allParams["access_token"] = token
}
// 添加业务参数
for k, v := range params {
allParams[k] = ToString(v)
}
// 构建sign
sign := CreateSign(allParams, client.PrivateKey, "RSA2")
allParams["sign"] = sign
return allParams
}
func (client OpenClient) Execute(iRequest IRequest) []byte {
return client.ExecuteToken(iRequest, "")
}

View File

@@ -0,0 +1,99 @@
package common
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"sort"
"strings"
)
const (
PEM_BEGIN = "-----BEGIN RSA PRIVATE KEY-----\n"
PEM_END = "\n-----END RSA PRIVATE KEY-----"
)
func CreateSign(allParams map[string]string, privateKey string, signType string) string {
signContent := GetSignContent(allParams)
return Sign(signContent, privateKey, signType)
}
func Sign(signContent string, privateKey string, signType string) string {
if signType == "RSA" {
return RsaSign(signContent, privateKey, crypto.SHA1)
} else if signType == "RSA2" {
return RsaSign(signContent, privateKey, crypto.SHA256)
} else {
panic(errors.New("signType错误"))
}
}
func RsaSign(signContent string, privateKey string, hash crypto.Hash) string {
shaNew := hash.New()
shaNew.Write([]byte(signContent))
hashed := shaNew.Sum(nil)
priKey, err := ParsePrivateKey(privateKey)
if err != nil {
panic(err)
}
signature, err := rsa.SignPKCS1v15(rand.Reader, priKey, hash, hashed)
if err != nil {
panic(err)
}
return base64.StdEncoding.EncodeToString(signature)
}
func ParsePrivateKey(privateKey string)(*rsa.PrivateKey, error) {
privateKey = FormatPrivateKey(privateKey)
// 2、解码私钥字节生成加密对象
block, _ := pem.Decode([]byte(privateKey))
if block == nil {
return nil, errors.New("私钥信息错误!")
}
// 3、解析DER编码的私钥生成私钥对象
priKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return priKey, nil
}
func FormatPrivateKey(privateKey string) string {
if !strings.HasPrefix(privateKey, PEM_BEGIN) {
privateKey = PEM_BEGIN + privateKey
}
if !strings.HasSuffix(privateKey, PEM_END) {
privateKey = privateKey + PEM_END
}
return privateKey
}
/**
1.筛选并排序
获取所有请求参数不包括字节类型参数如文件、字节流剔除sign字段剔除值为空的参数并按照参数名ASCII码递增排序字母升序排序
如果遇到相同字符则按照第二个字符的键值ASCII码递增排序以此类推。
2.拼接
将排序后的参数与其对应值,组合成“参数=参数值”的格式,并且把这些参数用&字符连接起来,此时生成的字符串为待签名字符串。
*/
func GetSignContent(allParams map[string]string) string {
keys := make([]string, 0, len(allParams))
var result []string
for k := range allParams {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
val := allParams[key]
if len(val) > 0 {
result = append(result, key + "=" + val)
}
}
return strings.Join(result, "&")
}

View File

@@ -0,0 +1,56 @@
package common
import (
"encoding/json"
"strconv"
)
func ToString(value interface{}) string {
var key string
switch value.(type) {
case float64:
ft := value.(float64)
key = strconv.FormatFloat(ft, 'f', -1, 64)
case float32:
ft := value.(float32)
key = strconv.FormatFloat(float64(ft), 'f', -1, 64)
case int:
it := value.(int)
key = strconv.Itoa(it)
case uint:
it := value.(uint)
key = strconv.Itoa(int(it))
case int8:
it := value.(int8)
key = strconv.Itoa(int(it))
case uint8:
it := value.(uint8)
key = strconv.Itoa(int(it))
case int16:
it := value.(int16)
key = strconv.Itoa(int(it))
case uint16:
it := value.(uint16)
key = strconv.Itoa(int(it))
case int32:
it := value.(int32)
key = strconv.Itoa(int(it))
case uint32:
it := value.(uint32)
key = strconv.Itoa(int(it))
case int64:
it := value.(int64)
key = strconv.FormatInt(it, 10)
case uint64:
it := value.(uint64)
key = strconv.FormatUint(it, 10)
case string:
key = value.(string)
case []byte:
key = string(value.([]byte))
default:
newValue, _ := json.Marshal(value)
key = string(newValue)
}
return key
}