wd.go 3.0 KB
package wangdian

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"github.com/gogf/gf/encoding/gjson"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/os/gtime"
	"github.com/gogf/gf/util/gconv"
	"net/url"
	"sort"
	"strings"
	"time"
	"unicode/utf8"
)

var server *Config

//万店
const pkgName = "wandian"

type Config struct {
	Sid       string
	Appkey    string
	AppSecret string
	ApiUrl    string
}

func New(req *Config) {
	server = req
	return
}

func packData(req map[string]interface{}) string {
	// 1. 提取并排序键名
	keys := make([]string, 0, len(req))
	for k := range req {
		if k == "sign" {
			continue
		}
		keys = append(keys, k)
	}
	sort.Strings(keys)

	// 2. 使用 strings.Builder 高效拼接字符串
	var builder strings.Builder

	// 3. 遍历排序后的键
	for i, key := range keys {
		val := req[key]

		// 非首个元素时添加分隔符
		if i > 0 {
			builder.WriteString(";")
		}

		// 4. 处理键部分
		keyLen := utf8.RuneCountInString(key)
		builder.WriteString(fmt.Sprintf("%02d-", keyLen))
		builder.WriteString(key)
		builder.WriteString(":")

		// 5. 处理值部分
		valLen := utf8.RuneCountInString(gconv.String(val))
		builder.WriteString(fmt.Sprintf("%04d-", valLen))
		builder.WriteString(gconv.String(val))
	}

	return builder.String()
}

// 带错误处理的增强版本
func makeSignSecure(req map[string]interface{}, appSecret string) map[string]interface{} {

	data := packData(req)
	if data == "" {
		return req
	}
	combined := data + appSecret
	hash := md5.Sum([]byte(combined))
	req["sign"] = hex.EncodeToString(hash[:])
	return req
}

//除空数组
func deleteZeroValues(req map[string]interface{}) map[string]interface{} {
	param := g.Map{}
	for k, v := range req {
		if gconv.String(v) != "" {
			param[k] = v
		}
	}
	return param
}

func post(ctx context.Context, method string, req interface{}) (res string, err error) {

	Start := gtime.TimestampMilli()
	reqMap := gconv.Map(req)
	reqMap["sid"] = server.Sid
	reqMap["appkey"] = server.Appkey
	reqMap["timestamp"] = time.Now().Unix()
	reqMap = deleteZeroValues(reqMap)
	reqMap = makeSignSecure(reqMap, server.AppSecret)

	param := gjson.New(reqMap)
	Url := server.ApiUrl + method
	Request := g.Client()
	Request.SetHeader("Content-Type", "application/x-www-form-urlencoded")
	Request.SetHeader("Content-length", fmt.Sprintf("%d", len(param.MustToJsonString())))

	postData := url.Values{}
	for k, v := range param.Map() {
		postData.Add(k, gconv.String(v))
	}
	encoded := postData.Encode()

	resp, err := Request.Timeout(time.Second*10).Post(Url, encoded)
	defer func() {
		_ = resp.Close()
		ctx = context.WithValue(ctx, "Method", "POST")
		ctx = context.WithValue(ctx, "URI", Url)
		if err != nil {
			g.Log().Ctx(ctx).Cat(pkgName).Cat("error").Infof("参数【%v】错误【%v】响应时间【%v ms】", param.MustToJsonString(), err.Error(), gtime.TimestampMilli()-Start)
		} else {
			g.Log().Ctx(ctx).Cat(pkgName).Infof("参数【%v】响应【%v】响应时间【%v ms】", param.MustToJsonString(), res, gtime.TimestampMilli()-Start)
		}
	}()
	res = resp.ReadAllString()
	return
}