import hashlib
import hmac
import json
import requests
def generate_signature(body: str, api_secret: str, timestamp: int) -> str:
"""
生成签名
Args:
body: 请求体字符串
api_secret: 商户密钥
timestamp: 时间戳(秒)
Returns:
签名字符串
"""
# 拼接签名字符串
sign_string = f"{body}|{timestamp}"
# 计算HMAC-SHA256签名
signature = hmac.new(
api_secret.encode('utf-8'),
sign_string.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
def generate_headers(merchant_id: str, api_key: str, api_secret: str, body: dict, timestamp: int = None):
"""
生成带签名的请求头部
Args:
merchant_id: 商户ID
api_key: API Key
api_secret: 商户密钥
body: 请求体字典
timestamp: 时间戳,默认为当前时间
Returns:
请求头部字典
"""
if timestamp is None:
# 将body转换为JSON字符串
# body_string = json.dumps(body, separators=(',', ':'), ensure_ascii=False)
body_string = json.dumps(body, ensure_ascii=False)
# 生成签名
signature = generate_signature(body_string, api_secret, timestamp)
# 返回请求头部
return {
'X-MERCHANT-ID': merchant_id,
'X-API-KEY': api_key,
'X-SIGN': signature,
'X-TIMESTAMP': str(timestamp),
'Content-Type': 'application/json'
}
def create_order(headers, data, timestamp=None):
url = "https://y...content-available-to-author-only...d.xyz/api/payment/create_orders"
try:
request_body = json.dumps(data, ensure_ascii=False)
# 打印请求参数详情
print("\n=== 创建订单 ===")
print(f"请求URL: {url}")
print(f"请求方法: POST")
print(f"请求体 (格式化JSON):")
print(json.dumps(data, ensure_ascii=False, indent=2))
print(f"请求体 (原始字符串): {request_body}")
if timestamp:
print(f"时间戳: {timestamp}")
print(f"签名原始字符串: {request_body}|{timestamp}")
print("请求头部:")
for key, value in headers.items():
print(f" {key}: {value}")
print("=" * 40)
resp = requests.post(url, data=request_body, headers=headers, timeout=10)
# 打印响应数据详情
print(f"\n=== 创建订单接口响应数据 ===")
print(f"响应状态码: {resp.status_code}")
print(f"响应内容 (原始): {resp.text}")
if resp.status_code == 200:
try:
response_data = resp.json()
print(f"响应内容 (格式化JSON):")
print(json.dumps(response_data, ensure_ascii=False, indent=2))
print("=" * 40)
return response_data
except json.JSONDecodeError:
print(f"响应不是有效的JSON格式")
print("=" * 40)
return None
else:
print("=" * 40)
return None
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
def query_order(headers, out_trade_no):
url = "https://y...content-available-to-author-only...d.xyz/api/payment/query_orders_status"
data = {
"out_trade_no": out_trade_no
}
try:
resp = requests.post(url, data=json.dumps(data), headers=headers, timeout=10)
print(f"\n查询订单响应状态码: {resp.status_code}")
print(f"查询订单响应内容: {resp.text}")
if resp.status_code == 200:
response_data = resp.json()
return response_data
else:
return None
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
def refund_order(headers, out_trade_no):
"""
订单退款接口
Args:
headers: 请求头部字典
out_trade_no: 需要退款的支付订单编号
Returns:
响应数据字典,如果请求失败则返回 None
"""
url = "https://y...content-available-to-author-only...d.xyz/api/payment/orders_refund"
data = {
"out_trade_no": out_trade_no
}
try:
request_body = json.dumps(data, ensure_ascii=False)
print(f"\n发送请求:")
print(f"URL: {url}")
print(f"请求体: {request_body}")
resp = requests.post(url, data=request_body, headers=headers, timeout=10)
print(f"\n订单退款响应状态码: {resp.status_code}")
print(f"订单退款响应内容: {resp.text}")
if resp.status_code == 200:
response_data = resp.json()
return response_data
else:
return None
except requests.RequestException as e:
print(f"请求失败: {e}")
return None
# 使用示例
if __name__ == "__main__":
# api link: https://y...content-available-to-author-only...d.xyz
# api_secret: 7d5bcedf57f6460f20e22895532273f695ec940acb3bf118
# key: sk_d987cc44b7ae5bef0b15618a
api_secret = "7d5bcedf57f6460f20e22895532273f695ec940acb3bf118"
api_key = 'sk_d987cc44b7ae5bef0b15618a'
merchant_id = "MCH007881CF6E42C6"
# 调用创建订单接口
body_data = {
"amount": "100.00",
"symbol": "usd",
"attach": "Create an order"
}
create_timestamp
= int(time.
time()) - 5 * 60 create_headers = generate_headers(
merchant_id=merchant_id,
api_key=api_key,
api_secret=api_secret,
body=body_data,
timestamp=create_timestamp
)
# 调用创建订单接口
create_response = create_order(create_headers, body_data, create_timestamp)
# 从创建订单响应中获取 out_trade_no(可选,用于后续退款)
out_trade_no = None
if create_response:
if 'data' in create_response and isinstance(create_response['data'], dict) and 'out_trade_no' in create_response['data']:
out_trade_no = create_response['data']['out_trade_no']
elif 'out_trade_no' in create_response:
out_trade_no = create_response['out_trade_no']
# 使用固定的订单号请求退款接口(如果创建订单失败或需要测试特定订单)
if not out_trade_no:
out_trade_no = "YA20260106103346813599"
print(f"\n使用订单号进行退款: {out_trade_no}")
# 订单退款接口
refund_data = {
"out_trade_no": out_trade_no
}
# 为退款接口生成请求头和签名
refund_headers = generate_headers(
merchant_id=merchant_id,
api_key=api_key,
api_secret=api_secret,
body=refund_data,
timestamp=refund_timestamp
)
print("\n订单退款请求头部:")
for key, value in refund_headers.items():
print(f"{key}: {value}")
# 打印请求参数详情
print("\n=== 订单退款 ===")
print(f"请求URL: https://y...content-available-to-author-only...d.xyz/api/payment/orders_refund")
print(f"请求方法: POST")
print(f"请求体 (JSON): {json.dumps(refund_data, ensure_ascii=False, indent=2)}")
print(f"时间戳: {refund_timestamp}")
print(f"签名原始字符串: {json.dumps(refund_data, ensure_ascii=False)}|{refund_timestamp}")
print("=" * 40)
# 调用订单退款接口
refund_response = refund_order(refund_headers, out_trade_no)