|
- package comm
-
- import (
- "bytes"
- "crypto/md5"
- "crypto/tls"
- "encoding/hex"
- "encoding/json"
- "errors"
- "io"
- "io/ioutil"
- "net/http"
- "net/url"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/bitly/go-simplejson"
- "github.com/nilorg/sdk/convert"
- )
-
- var (
- /**公用方法**/
- // Session 用户登录授权成功后,TOP颁发给应用的授权信息。当此API的标签上注明:“需要授权”,则此参数必传;“不需要授权”,则此参数不需要传;“可选授权”,则此参数为可选
- Session string
- // Timeout ...
- Timeout time.Duration
- // CacheExpiration 缓存过期时间
- CacheExpiration = time.Hour
- // GetCache 获取缓存
- GetCache getCacheFunc
- // SetCache 设置缓存
- SetCache setCacheFunc
-
- /**淘宝平台信息**/
- TaobaoAppKey string
- TaobaoAppSecret string
- TaobaoRouter string
- TaobaoVersion = "2.0"
-
- /**京东平台信息**/
- JDAppKey string
- JDAppSecret string
- JDRouter string
- JDSdkRouter string
- JDVersion = "2.0"
-
- /**拼多多平台信息**/
- PDDAppKey string
- PDDAppSecret string
- PDDRouter string
- PDDVersion = "v1.0"
-
- /**考拉海购平台信息**/
- KaolaAppKey string
- KaolaAppSecret string
- KaolaRouter string
- KaolaVersion = "1.0"
- )
-
- // Arg 参数
- type Arg map[string]interface{}
-
- // copyArg 复制参数
- func copyArg(srcArgs Arg) Arg {
- newArgs := make(Arg)
- for key, value := range srcArgs {
- newArgs[key] = value
- }
- return newArgs
- }
-
- // newCacheKey 创建缓存Key
- func newCacheKey(p Arg) string {
- cpArgs := copyArg(p)
- delete(cpArgs, "session")
- delete(cpArgs, "timestamp")
- delete(cpArgs, "sign")
-
- keys := []string{}
- for k := range cpArgs {
- keys = append(keys, k)
- }
- // 排序asc
- sort.Strings(keys)
- // 把所有参数名和参数值串在一起
- cacheKeyBuf := new(bytes.Buffer)
- for _, k := range keys {
- cacheKeyBuf.WriteString(k)
- cacheKeyBuf.WriteString("=")
- cacheKeyBuf.WriteString(interfaceToString(cpArgs[k]))
- }
- h := md5.New()
- io.Copy(h, cacheKeyBuf)
- return hex.EncodeToString(h.Sum(nil))
- }
-
- // execute 执行API接口
- func execute(p Arg, router string) (bytes []byte, err error) {
- err = checkConfig()
- if err != nil {
- return
- }
-
- var req *http.Request
- req, err = http.NewRequest("POST", router, strings.NewReader(p.getReqData()))
- if err != nil {
- return
- }
- tr := &http.Transport{
- TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
- }
- req.Header.Add("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
- httpClient := &http.Client{Transport: tr}
- httpClient.Timeout = Timeout
- var resp *http.Response
- resp, err = httpClient.Do(req)
- if err != nil {
- return
- }
-
- if resp.StatusCode != 200 {
- err = errors.New("请求错误:" + strconv.Itoa(resp.StatusCode))
- return
- }
-
- defer resp.Body.Close()
- bytes, err = ioutil.ReadAll(resp.Body)
- // fmt.Printf("\n\n\nreq: %v\n\nresp: %v\n\n\n", p.getReqData(), string(bytes))
- return
- }
-
- // Execute 执行API接口
- func Execute(method string, p Arg) (res *simplejson.Json, err error) {
- p, r := setReqData(p, method)
- var bodyBytes []byte
- bodyBytes, err = execute(p, r)
- if err != nil {
- return
- }
-
- return bytesToResult(bodyBytes)
- }
-
- func bytesToResult(bytes []byte) (res *simplejson.Json, err error) {
- res, err = simplejson.NewJson(bytes)
- if err != nil {
- return
- }
- if responseError, ok := res.CheckGet("error_response"); ok {
- if subMsg, subOk := responseError.CheckGet("sub_msg"); subOk {
- err = errors.New(subMsg.MustString())
- } else if zhDesc, descOk := responseError.CheckGet("zh_desc"); descOk {
- err = errors.New(zhDesc.MustString())
- } else {
- err = errors.New(responseError.Get("msg").MustString())
- }
- res = nil
- }
- return
- }
-
- // ExecuteCache 执行API接口,缓存
- func ExecuteCache(method string, param Arg) (res *simplejson.Json, err error) {
- p, r := setReqData(param, method)
-
- cacheKey := newCacheKey(p)
- // 获取缓存
- if GetCache != nil {
- cacheBytes := GetCache(cacheKey)
- if len(cacheBytes) > 0 {
- res, err = simplejson.NewJson(cacheBytes)
- if err == nil && res != nil {
- return
- }
- }
- }
-
- var bodyBytes []byte
- bodyBytes, err = execute(param, r)
- if err != nil {
- return
- }
- res, err = bytesToResult(bodyBytes)
- if err != nil {
- return
- }
- ejsonBody, _ := res.MarshalJSON()
- // 设置缓存
- if SetCache != nil {
- go SetCache(cacheKey, ejsonBody, CacheExpiration)
- }
- return
- }
-
- // 检查配置
- func checkConfig() error {
- if TaobaoAppKey == "" && JDAppKey == "" && KaolaAppKey == "" && PDDAppKey == "" {
- return errors.New("至少需要设置一个平台参数")
- }
- return nil
- }
-
- //组装参数及添加公共参数
- func setReqData(p Arg, method string) (Arg, string) {
- platform := strings.Split(method, ".")[0]
- router := ""
- hh, _ := time.ParseDuration("8h")
- loc := time.Now().UTC().Add(hh)
- if platform == "taobao" {
- //淘宝
- p["timestamp"] = strconv.FormatInt(loc.Unix(), 10)
- p["partner_id"] = "Blant"
- p["app_key"] = TaobaoAppKey
- p["v"] = TaobaoVersion
- if Session != "" {
- p["session"] = Session
- }
- p["method"] = method
- p["format"] = "json"
- p["sign_method"] = "md5"
- // 设置签名
- p["sign"] = getSign(p, TaobaoAppSecret)
- router = TaobaoRouter
- } else if platform == "jdSdk" || platform == "jd" {
- //京东
- param := p
- p = Arg{}
- p["param_json"] = param
- p["app_key"] = JDAppKey
- p["v"] = JDVersion
- p["timestamp"] = loc.Format("2006-01-02 15:04:05")
- p["method"] = method
- p["format"] = "json"
- p["sign_method"] = "md5"
- // 设置签名
- p["sign"] = getSign(p, JDAppSecret)
- router = JDSdkRouter
- if platform == "jd" {
- router = JDRouter
- }
- } else if platform == "pdd" {
- //拼多多
- p["type"] = method
- p["data_type"] = "json"
- p["version"] = PDDVersion
- p["client_id"] = PDDAppKey
- p["timestamp"] = strconv.FormatInt(loc.Unix(), 10)
- // 设置签名
- p["sign"] = getSign(p, PDDAppSecret)
- router = PDDRouter
- } else if platform == "kaola" {
- //考拉海购
- p["method"] = method
- p["v"] = KaolaVersion
- p["signMethod"] = "md5"
- p["unionId"] = KaolaAppKey
- p["timestamp"] = loc.Format("2006-01-02 15:04:05")
- // 设置签名
- p["sign"] = getSign(p, KaolaAppSecret)
- router = KaolaRouter
- } else if platform == "suning" {
- // TODO 苏宁
-
- } else if platform == "vip" {
- // TODO 唯品会
- }
-
- return p, router
- }
-
- // 获取请求数据
- func (p Arg) getReqData() string {
- // 公共参数
- args := url.Values{}
- // 请求参数
- for key, val := range p {
- args.Set(key, interfaceToString(val))
- }
- return args.Encode()
- }
-
- // 获取签名
- func getSign(p Arg, secret string) string {
- // 获取Key
- var keys []string
- for k := range p {
- keys = append(keys, k)
- }
- // 排序asc
- sort.Strings(keys)
- // 把所有参数名和参数值串在一起
- query := bytes.NewBufferString(secret)
- for _, k := range keys {
- query.WriteString(k)
- query.WriteString(interfaceToString(p[k]))
- }
- query.WriteString(secret)
- // 使用MD5加密
- h := md5.New()
- _, _ = io.Copy(h, query)
- // 把二进制转化为大写的十六进制
- return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
- }
-
- func interfaceToString(src interface{}) string {
- if src == nil {
- panic(ErrTypeIsNil)
- }
- switch src.(type) {
- case string:
- return src.(string)
- case int, int8, int32, int64:
- case uint8, uint16, uint32, uint64:
- case float32, float64:
- return convert.ToString(src)
- }
- data, err := json.Marshal(src)
- if err != nil {
- panic(err)
- }
- return string(data)
- }
|