提交 f21630ce authored 作者: 屈传平's avatar 屈传平

ikucun

上级 3e6bc5ce
package main
import (
"context"
"gitlab.jxhh.com/stbz/library.git/upstream/ikucun"
)
func main() {
config := ikucun.Config{}
config.AppSecret = "d6bfa503b81641c88a8ec22ff1728e44"
config.AppId = "7dca552382b0407f8b7ebc965d53e72e"
config.AccessToken = "efa79a299fec4ef58a606486544fe30d"
config.ApiUrl = "https://openapi-stable.akucun.com/route/rest"
ikucun.New(&config)
activityList := ikucun.ActivityListReq{}
activityList.PageIndex = "1"
activityList.PageSize = "10"
ikucun.Activity.List(context.Background(), activityList)
}
...@@ -2,62 +2,176 @@ package ikucun ...@@ -2,62 +2,176 @@ package ikucun
import ( import (
"context" "context"
"github.com/gogf/gf/crypto/gsha1" "crypto/sha1"
"encoding/hex"
"fmt"
"github.com/gogf/gf/encoding/gjson" "github.com/gogf/gf/encoding/gjson"
"github.com/gogf/gf/frame/g" "github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gtime" "github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/util/gconv"
"math/rand" "math/rand"
"net/url"
"sort"
"strings"
"time" "time"
) )
var server *Config var server *Config
func New(req *Config) {
server = req
return
}
const pkgName = "ikucun" const pkgName = "ikucun"
type Config struct { type Config struct {
AppId string AppId string
AppSecret string AppSecret string
ApiUrl string ApiUrl string
AccessToken string
} }
// 生成随机 nonce 字符串 (等效 JS 的 makeNonceStr)
func makeNonceStr() string { func makeNonceStr() string {
str := "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789" // 原始有效字符集(排除易混淆字符)
rand.Seed(time.Now().UnixNano()) // 初始化随机数种子 const baseStr = "abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ23456789"
// 打乱字符串 // 打乱字符顺序(Go 的稳定洗牌算法)
shuffledStr := shuffleString(str) shuffled := []rune(baseStr)
rand.Seed(time.Now().UnixNano())
rand.Shuffle(len(shuffled), func(i, j int) {
shuffled[i], shuffled[j] = shuffled[j], shuffled[i]
})
// 随机截取 10 位字符
start := rand.Intn(len(shuffled) - 10)
return string(shuffled[start : start+10])
}
// 随机起始位置 // 构建签名前字符串 (等效 JS 的 beforeSignBuild)
startIndex := rand.Intn(len(shuffledStr) - 10) func beforeSignBuild(nonceStr, interfaceName string, queryParams map[string]string, body string) string {
// 处理空参数
if queryParams == nil {
queryParams = make(map[string]string)
}
// 截取 10 位字符 // 准备 POST 参数
return shuffledStr[startIndex : startIndex+10] postParams := make(map[string]string)
if body != "" {
postParams["body"] = body
}
// 获取公共参数
appSecret := server.AppSecret
timestamp := time.Now().Unix() // 直接获取秒级时间戳
commonParams := map[string]string{
"appid": queryParams["appid"],
"noncestr": nonceStr,
"timestamp": fmt.Sprintf("%d", timestamp),
"version": queryParams["version"],
"appsecret": appSecret,
"format": queryParams["json"],
"interfaceName": interfaceName,
}
// 合并参数(注意合并顺序)
allParams := make(map[string]string)
for k, v := range commonParams {
allParams[k] = v
}
for k, v := range queryParams {
allParams[k] = v
}
for k, v := range postParams {
allParams[k] = v
}
// 按键名排序
keys := make([]string, 0, len(allParams))
for k := range allParams {
keys = append(keys, k)
}
sort.Strings(keys)
// 构建签名字符串
var builder strings.Builder
for i, k := range keys {
if i > 0 {
builder.WriteString("&")
}
builder.WriteString(fmt.Sprintf("%s=%s", k, allParams[k]))
}
return builder.String()
} }
// 打乱字符串 func getQueryParams(interfaceName, body string) map[string]string {
func shuffleString(str string) string {
strRunes := []rune(str) // 生成 nonce 并添加到查询参数
rand.Shuffle(len(strRunes), func(i, j int) { nonceStr := makeNonceStr()
strRunes[i], strRunes[j] = strRunes[j], strRunes[i] timestamp := time.Now().Unix() // 直接获取秒级时间戳
}) queryParams := map[string]string{
return string(strRunes) "appid": server.AppId,
"version": "1.0",
"format": "json",
"timestamp": fmt.Sprintf("%d", timestamp),
"interfaceName": interfaceName,
"accessToken": server.AccessToken,
// 其他查询参数...
}
queryParams["noncestr"] = nonceStr
// 构建签名前字符串
signStr := beforeSignBuild(
nonceStr,
interfaceName,
queryParams,
body,
)
// 计算 SHA1 签名
hasher := sha1.New()
hasher.Write([]byte(signStr))
sign := hex.EncodeToString(hasher.Sum(nil))
// 添加签名到查询参数
queryParams["sign"] = sign
//res := gsha1.Encrypt(req)
return queryParams
} }
func sign(req string) string { // 处理 interface{} 类型的值
res := gsha1.Encrypt(req) func mapToSortedQuery(params map[string]string) string {
return res if len(params) == 0 {
return ""
}
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var builder strings.Builder
for i, k := range keys {
if i > 0 {
builder.WriteByte('&')
}
builder.WriteString(url.QueryEscape(k))
builder.WriteByte('=')
builder.WriteString(url.QueryEscape(params[k]))
}
return builder.String()
} }
func post(ctx context.Context, method string, req interface{}) (res string, err error) { func post(ctx context.Context, method string, req interface{}) (res string, err error) {
Start := gtime.TimestampMilli() Start := gtime.TimestampMilli()
reqMap := gconv.Map(req) param := gjson.New(req)
reqMap["appId"] = server.AppId queryParam := getQueryParams(method, param.MustToJsonString())
param := gjson.New(reqMap) Url := server.ApiUrl + "?" + mapToSortedQuery(queryParam)
Url := server.ApiUrl + method
Request := g.Client() Request := g.Client()
Request.SetHeader("Content-Type", "application/json") Request.SetHeader("Content-Type", "application/json")
Request.SetHeader("sign", sign(param.MustToJsonString()))
resp, err := Request.Timeout(time.Second*5).Post(Url, param.MustToJsonString()) resp, err := Request.Timeout(time.Second*5).Post(Url, param.MustToJsonString())
defer func() { defer func() {
_ = resp.Close() _ = resp.Close()
......
package ikucun
import (
"context"
"github.com/gogf/gf/encoding/gjson"
)
type activityIkc struct {
}
//Activity 活动
var Activity = activityIkc{}
type ActivityListReq struct {
PageIndex string `json:"pageIndex"`
PageSize string `json:"pageSize"`
}
type ActivityListRes struct {
Code string `json:"code"`
Success bool `json:"success"`
Message string `json:"message"`
Data struct {
ActivityList []struct {
ActivityId string `json:"activityId"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
ActiveType int `json:"activeType"`
UpDownStatus int `json:"upDownStatus"`
} `json:"activityList"`
} `json:"data"`
}
//List 列表
func (*activityIkc) List(ctx context.Context, req ActivityListReq) (res *ActivityListRes, err error) {
method := "mengxiang.supply.consignment.activity.search"
result, err := post(ctx, method, req)
_ = gjson.New(result).Scan(&res)
return
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论