增加发货平台 2

This commit is contained in:
yml2213
2026-07-07 08:51:23 +08:00
parent fb0ec5085f
commit c101b5f359
10 changed files with 640 additions and 1 deletions
+231
View File
@@ -0,0 +1,231 @@
鉴权
每个请求在 Header 携带:
Header 说明
X-App-Key App Key
X-Timestamp Unix 秒级时间戳(字符串),与服务器相差不超过 5 分钟
X-Sign 签名(见下)
#签名算法
code
待签名字符串 = app_key + timestamp + raw_json_body
sign = HMAC_SHA256(待签名字符串, app_secret) // 小写十六进制
要点 说明
raw_json_body 与 HTTP Body 完全一致 的原始字符串;签名后再原样发送
是否排序 不需要对 JSON 字段排序;勿解析后再 json_encode 一次
Header app_key、timestamp 只放在 Header,不参与 Body JSON
中文 PHP 使用 JSON_UNESCAPED_UNICODEPython 使用 ensure_ascii=False
商户后台 开放 API → 调用调试 需先通过密码或动态口令验证,方可加载密钥并查看待签名字符串、签名结果与最终发包参数。
#PHP
php
<?php
$appKey = 'your_app_key';
$appSecret = 'your_app_secret';
$apiBase = 'http://skin-exchange.yiquyou.icu';
$payload = [
'platform_order_no' => 'YOUR-ORDER-001',
'product_code' => '10000001',
'platform_buy_num' => 1,
];
// 生成 body 后不要再改,签名与 curl 必须用同一字符串
$body = json_encode($payload, JSON_UNESCAPED_UNICODE);
$timestamp = (string) time();
$preSign = $appKey . $timestamp . $body;
$sign = hash_hmac('sha256', $preSign, $appSecret);
$ch = curl_init($apiBase . '/api/open/v1/orders/store');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'X-App-Key: ' . $appKey,
'X-Timestamp: ' . $timestamp,
'X-Sign: ' . $sign,
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
#Java
依赖 JDK 标准库(javax.crypto),无需第三方包。
java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
public class OpenApiSignExample {
private static String hmacSha256Hex(String secret, String message) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
StringBuilder hex = new StringBuilder(hash.length * 2);
for (byte b : hash) {
hex.append(String.format("%02x", b));
}
return hex.toString();
}
public static void main(String[] args) throws Exception {
String appKey = "your_app_key";
String appSecret = "your_app_secret";
String apiBase = "http://skin-exchange.yiquyou.icu";
// 与最终请求体一致;可用 Gson/Jackson 生成,但不要签名后再格式化
String body = "{\"platform_order_no\":\"YOUR-ORDER-001\",\"product_code\":\"10000001\",\"platform_buy_num\":1}";
String timestamp = String.valueOf(Instant.now().getEpochSecond());
String preSign = appKey + timestamp + body;
String sign = hmacSha256Hex(appSecret, preSign);
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(apiBase + "/api/open/v1/orders/store"))
.header("Content-Type", "application/json")
.header("X-App-Key", appKey)
.header("X-Timestamp", timestamp)
.header("X-Sign", sign)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}
#Python
Python 3hmac + hashlib 标准库。
python
import hashlib
import hmac
import json
import time
import urllib.request
APP_KEY = "your_app_key"
APP_SECRET = "your_app_secret"
API_BASE = "http://skin-exchange.yiquyou.icu"
payload = {
"platform_order_no": "YOUR-ORDER-001",
"product_code": "10000001",
"platform_buy_num": 1,
}
# separators 生成紧凑 JSON,与常见 PHP json_encode 一致;签名后勿再 dumps
body = json.dumps(payload, ensure_ascii=False, separators=(",", ":"))
timestamp = str(int(time.time()))
pre_sign = APP_KEY + timestamp + body
sign = hmac.new(
APP_SECRET.encode("utf-8"),
pre_sign.encode("utf-8"),
hashlib.sha256,
).hexdigest()
req = urllib.request.Request(
API_BASE + "/api/open/v1/orders/store",
data=body.encode("utf-8"),
method="POST",
headers={
"Content-Type": "application/json",
"X-App-Key": APP_KEY,
"X-Timestamp": timestamp,
"X-Sign": sign,
},
)
with urllib.request.urlopen(req) as resp:
print(resp.status)
print(resp.read().decode())
使用 requests 时:
python
import requests
resp = requests.post(
API_BASE + "/api/open/v1/orders/store",
data=body.encode("utf-8"), # 传 bytes,避免库再次序列化
headers={
"Content-Type": "application/json",
"X-App-Key": APP_KEY,
"X-Timestamp": timestamp,
"X-Sign": sign,
},
timeout=30,
)
print(resp.status_code, resp.text)
#Go
go
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func sign(appKey, appSecret, body string) (timestamp, sign string) {
timestamp = fmt.Sprintf("%d", time.Now().Unix())
mac := hmac.New(sha256.New, []byte(appSecret))
mac.Write([]byte(appKey + timestamp + body))
sign = hex.EncodeToString(mac.Sum(nil))
return
}
func main() {
appKey := "your_app_key"
appSecret := "your_app_secret"
apiBase := "http://skin-exchange.yiquyou.icu"
// 建议用 struct + json.Marshal;保证签名用的 body 与 Post 发送的字节一致
type orderReq struct {
PlatformOrderNo string `json:"platform_order_no"`
ProductCode string `json:"product_code"`
PlatformBuyNum int `json:"platform_buy_num"`
}
bodyBytes, _ := json.Marshal(orderReq{
PlatformOrderNo: "YOUR-ORDER-001",
ProductCode: "10000001",
PlatformBuyNum: 1,
})
body := string(bodyBytes)
timestamp, sig := sign(appKey, appSecret, body)
req, _ := http.NewRequest(http.MethodPost, apiBase+"/api/open/v1/orders/store", bytes.NewReader(bodyBytes))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("X-App-Key", appKey)
req.Header.Set("X-Timestamp", timestamp)
req.Header.Set("X-Sign", sig)
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(resp.Status, string(out))
}
#常见错误
现象 原因
签名校验失败 Body 与签名时不一致(多空格、字段顺序、Unicode 转义不同)
timestamp 无效或已过期 服务器时间差超过 5 分钟
缺少 app_key、timestamp 或 sign Header 名称或大小写错误(应为 X-App-Key 等)
排查:用商户后台 调用调试 对比「待签名字符串」与己方代码输出是否一致。