173 lines
4.4 KiB
Go
173 lines
4.4 KiB
Go
package alipayapi
|
|
|
|
import (
|
|
"crypto"
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"encoding/base64"
|
|
"encoding/pem"
|
|
"fmt"
|
|
"git.rosy.net.cn/baseapi/utils"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.rosy.net.cn/baseapi"
|
|
"git.rosy.net.cn/baseapi/platformapi"
|
|
)
|
|
|
|
const (
|
|
prodURL = "https://openapi.alipay.com/gateway.do"
|
|
|
|
signKey = "sign"
|
|
)
|
|
|
|
const (
|
|
CommonErrSuccess = "10000"
|
|
CommonErrServiceNotAvailable = "20000"
|
|
)
|
|
|
|
type API struct {
|
|
appID string
|
|
privateKey *rsa.PrivateKey
|
|
client *http.Client
|
|
config *platformapi.APIConfig
|
|
}
|
|
|
|
type KeyMobile struct {
|
|
Code string `json:"code"`
|
|
Msg string `json:"msg"`
|
|
Mobile string `json:"mobile"`
|
|
}
|
|
|
|
var (
|
|
commonCanRetryErrMap = map[string]bool{
|
|
CommonErrServiceNotAvailable: true,
|
|
}
|
|
)
|
|
|
|
func New(appID string, privateKey interface{}, config ...*platformapi.APIConfig) (a *API) {
|
|
curConfig := platformapi.DefAPIConfig
|
|
if len(config) > 0 {
|
|
curConfig = *config[0]
|
|
}
|
|
var keyBytes []byte
|
|
if keyBytes2, ok := privateKey.([]byte); ok {
|
|
keyBytes = keyBytes2
|
|
} else {
|
|
keyBytes, _ = ioutil.ReadFile(privateKey.(string))
|
|
}
|
|
pubPem, _ := pem.Decode(keyBytes)
|
|
if pubPem == nil {
|
|
keyBytes, _ = base64.StdEncoding.DecodeString(string(keyBytes))
|
|
} else {
|
|
keyBytes = pubPem.Bytes
|
|
}
|
|
a = &API{
|
|
appID: appID,
|
|
client: &http.Client{Timeout: curConfig.ClientTimeout},
|
|
config: &curConfig,
|
|
}
|
|
if privateKey, err := x509.ParsePKCS1PrivateKey(keyBytes); err == nil {
|
|
a.privateKey = privateKey
|
|
} else {
|
|
baseapi.SugarLogger.Errorf("alpayapi.New failed with err:%v", err)
|
|
}
|
|
return a
|
|
}
|
|
|
|
func (a *API) GetAppID() string {
|
|
return a.appID
|
|
}
|
|
|
|
func (a *API) signParams(params map[string]interface{}) (sign string) {
|
|
keys := make([]string, 0)
|
|
for k := range params {
|
|
if k != signKey {
|
|
keys = append(keys, k)
|
|
}
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
strList := make([]string, len(keys))
|
|
for index, k := range keys {
|
|
strList[index] = fmt.Sprintf("%s=%v", k, params[k])
|
|
}
|
|
|
|
finalStr := strings.Join(strList, "&")
|
|
d := sha256.Sum256([]byte(finalStr))
|
|
signature, _ := rsa.SignPKCS1v15(rand.Reader, a.privateKey, crypto.SHA256, d[:])
|
|
sign = base64.StdEncoding.EncodeToString(signature)
|
|
return sign
|
|
}
|
|
|
|
func method2ResponseKey(method string) (responseKey string) {
|
|
responseKey = strings.Join(append(strings.Split(method, "."), "response"), "_")
|
|
return responseKey
|
|
}
|
|
|
|
func (a *API) AccessAPI(method string, params, bizContent map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
|
|
params = utils.MergeMaps(map[string]interface{}{
|
|
"app_id": a.GetAppID(),
|
|
"method": method,
|
|
"format": "JSON",
|
|
"charset": "utf-8",
|
|
"sign_type": "RSA2",
|
|
"version": "1.0",
|
|
}, params)
|
|
|
|
if len(bizContent) > 0 {
|
|
params["biz_content"] = string(utils.MustMarshal(bizContent))
|
|
}
|
|
|
|
err = platformapi.AccessPlatformAPIWithRetry(a.client,
|
|
func() *http.Request {
|
|
var request *http.Request
|
|
params["timestamp"] = utils.GetCurTimeStr()
|
|
params[signKey] = a.signParams(params)
|
|
|
|
fullURL := utils.GenerateGetURL(prodURL, "", params)
|
|
if isPost {
|
|
request, _ = http.NewRequest(http.MethodPost, prodURL, strings.NewReader(utils.Map2URLValues(bizContent).Encode()))
|
|
} else {
|
|
request, _ = http.NewRequest(http.MethodGet, fullURL, nil)
|
|
}
|
|
return request
|
|
},
|
|
a.config,
|
|
func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
|
|
if jsonResult1 == nil {
|
|
return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
|
|
}
|
|
if errorResponse, ok := jsonResult1["error_response"].(map[string]interface{}); ok {
|
|
retVal = errorResponse
|
|
} else {
|
|
retVal, _ = jsonResult1[method2ResponseKey(method)].(map[string]interface{})
|
|
if retVal == nil {
|
|
return platformapi.ErrLevelGeneralFail, fmt.Errorf("结果格式异常")
|
|
}
|
|
}
|
|
|
|
errCode := utils.Interface2String(retVal["code"])
|
|
if errCode != CommonErrSuccess && errCode != "" {
|
|
err = utils.NewErrorCode(utils.Interface2String(retVal["msg"]), errCode)
|
|
if commonCanRetryErrMap[errCode] {
|
|
return platformapi.ErrLevelRecoverableErr, err
|
|
}
|
|
errLevel = platformapi.ErrLevelGeneralFail
|
|
}
|
|
subErrCode := utils.Interface2String(retVal["sub_code"])
|
|
if subErrCode != "" {
|
|
return platformapi.ErrLevelCodeIsNotOK, utils.NewErrorCode(utils.Interface2String(retVal["sub_msg"]), subErrCode)
|
|
} else if err != nil {
|
|
return errLevel, err
|
|
}
|
|
|
|
return platformapi.ErrLevelSuccess, nil
|
|
})
|
|
return retVal, err
|
|
}
|