mirror of
https://gitee.com/durcframework/SOP.git
synced 2025-08-11 21:57:56 +08:00
3.2.0
This commit is contained in:
126
sop-sdk/sdk-go/common/HttpTool.go
Normal file
126
sop-sdk/sdk-go/common/HttpTool.go
Normal 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()
|
||||
// 得到完整的url,http://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
|
||||
}
|
||||
}
|
24
sop-sdk/sdk-go/common/IRequest.go
Normal file
24
sop-sdk/sdk-go/common/IRequest.go
Normal 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
|
||||
}
|
108
sop-sdk/sdk-go/common/OpenClient.go
Normal file
108
sop-sdk/sdk-go/common/OpenClient.go
Normal 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, "")
|
||||
}
|
99
sop-sdk/sdk-go/common/SignUtil.go
Normal file
99
sop-sdk/sdk-go/common/SignUtil.go
Normal 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, "&")
|
||||
}
|
56
sop-sdk/sdk-go/common/StringUtil.go
Normal file
56
sop-sdk/sdk-go/common/StringUtil.go
Normal 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
|
||||
}
|
Reference in New Issue
Block a user