简要描述:
通过自定义签名方法,调用开放平台接口
一、生成参数字符串
1. 按照请求参数名称将所有请求参数按照字母先后顺序排序 2. 然后将参数名和参数值进行拼接得到参数字符串 3. 如果请求参数中有嵌套json对象或者嵌套list对象的情况下,需要对嵌套的整个对象当作一个字符串按照1和2步骤处理 eg: Get请求:将arong=1,mrong=2,crong=3 ,排序为:arong=1, crong=3,mrong=2 ,拼接得到参数与值arong1crong3mrong2 POST请求:Json字符串转换成键值(key,vlaue)对象,再根据键排序,最后拼接得到key与value的字符串
二、生成签名
1. 签名字符串组合: timeStamp + nonce + app_secret + data; timeStamp: 当前时间(yyyyMMddHHmmss格式),nonce:随机数,app_secret:Api应用密匙,data :生成的参数字符串 2. MD5 加密,返回大写字符
三、调用接口
1. 请求头部加入签名
headers.Add("timestamp", timeStamp);
headers.Add("appid", App_ID);
headers.Add("nonce", nonce);
headers.Add("sign", sign);
2. 调用 WebApi
webapi请求地址、请求方式、请求参数 详见Api接口文档四、调用示例
php
<?php
$appid = "商户APPID";
$secret = "商户SECRET";
date_default_timezone_set('PRC');
$data = array(
'endordertime' => '2019-05-13 00:00:00',
'orderscope' => '0',
'packagestatus' => '-1',
'pageindex' => 1,
'pagesize' => 10,
'startordertime' => '2019-05-05 00:00:00',
);
function getSign($time,$nonce,$secret, $data) {
ksort($data);
$params = ToStrParams($data);
$sign =strtoupper (md5($time.$nonce.$secret.$params ));
return $sign;
}
function ToStrParams($data)
{
$buff = "";
foreach ($data as $k => $v)
{
$buff .= $k . $v;
}
return $buff;
}
$time=date("YmdHis");
$nonce='120';
$headers = array(
'timestamp:'. $time,
'appid:'. $appid,
'nonce:'. $nonce,
'sign:'. getSign($time,$nonce,$secret, $data),
"Content-type: application/json",
);
$url='http://openapi.weixin12315.com/api/sign/md.shop.order/v1/list';
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, TRUE);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$res = curl_exec($ch);
print( $res);
?>python
import hashlib
import datetime
import random
import requests
timeStamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
nonce = str(random.randint(1000, 9999))
secret = "商户SECRET"
appid = "商户APPID"
def data_string(data):
data_list = sorted(data.items(), key=lambda x: x[0])
data = data_sort(data_list)
return data
def data_sort(data):
data_str = ''
for i in data:
for j in i:
data_str += str(j)
return data_str
def get_sign(data):
sign_str = timeStamp + nonce + secret + data_string(data)
md5 = hashlib.md5()
md5.update(sign_str.encode("utf8"))
result = md5.hexdigest()
sign = result.upper()
return sign
def set_headers(params):
headers = {"timestamp": timeStamp,
"nonce": nonce,
"appId": appid,
"sign": get_sign(params),
"Content-Type": "application/json"
}
return headers
data = {
"endordertime": "2019-05-13 00:00:00",
"orderscope": "0",
"packagestatus": "-1",
"pageindex": 1,
"pagesize": 10,
"startordertime": "2019-05-05 00:00:00"
}
url = "http://openapi.weixin12315.com/api/sign/md.shop.order/v1/list"
req = requests.post(url, json=data, headers=set_headers(data)).json()
print(req)
data2 = {
"storageorderinfo": {"storageorderno": "storageorderno", "fcdealerno": "fcdealerno", "prolist": [{"productno": "1000", "productcount": "20"}], "warehouseno": "1", "syncpda": "1"}
}
for i, j in data2.items():
if type(j) == int:
data2[i] = j
else:
data2[i] = str(j).replace("'", "\"")
url2 = "https://openapi.weixin12315.com/api/sign/md.fc.store/v2/addOrder"
req2 = requests.post(url2, json=data2, headers=set_headers(data2)).json()
print(req2)Java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
// 可替换其他 JSON 库
import com.alibaba.fastjson2.JSON;
public class HttpRequestExample {
private static final String APPID = "商户APPID";
private static final String SECRET = "商户SECRET";
public static void main(String[] args) {
try {
// 设置时区
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
// 准备请求数据
Map<String, Object> data = new HashMap<>();
data.put("OrderNo", "test123");
data.put("OrderType", "saleOrder");
data.put("fcDealerNo", "12324");
// 准备产品列表
List<Map<String, Object>> productionList = new ArrayList<>();
// 添加第一个产品
Map<String, Object> product1 = new HashMap<>();
product1.put("ProductNO", "aaa");
product1.put("ProductCount", 5);
product1.put("OrderLineNumber", "1");
productionList.add(product1);
// 添加第二个产品
Map<String, Object> product2 = new HashMap<>();
product2.put("ProductNO", "3193i2i2391");
product2.put("ProductCount", 6);
product2.put("OrderLineNumber", "2");
productionList.add(product2);
// 将产品列表添加到主数据中
data.put("production", productionList);
// 获取时间戳
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String time = sdf.format(new Date());
String nonce = "120";
// 生成签名
String sign = getSign(time, nonce, SECRET, data);
// 设置请求头
Map<String, String> headers = new HashMap<>();
headers.put("timestamp", time);
headers.put("appid", APPID);
headers.put("nonce", nonce);
headers.put("sign", sign);
headers.put("Content-type", "application/json");
System.out.println("Headers: "+ JSON.toJSONString(headers));
// 将复杂对象转换为JSON字符串
String jsonStr = JSON.toJSONString(data);
System.out.println("Request: " + jsonStr);
// 发送请求
String url = "http://openapi.t.miduonet.com/api/sign/md.fc.product/v1/addzmzorder";
String response = sendPostRequest(url, headers, jsonStr);
System.out.println("Response: " + response);
} catch (Exception e) {
System.err.println("Error occurred: " + e.getClass().getName());
System.err.println("Error message: " + e.getMessage());
e.printStackTrace();
}
}
private static String getSign(String time, String nonce, String secret,Map<String, Object> data) throws Exception {
// 对数据进行排序(不区分大小写)
TreeMap<String, Object> sortedData = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
sortedData.putAll(data);
StringBuilder params = new StringBuilder();
for (Map.Entry<String, Object> entry : sortedData.entrySet()) {
String key = entry.getKey();
String value;
// 如果值是List类型(对应production数组),需要特殊处理
if (entry.getValue() instanceof List) {
value = JSON.toJSONString(entry.getValue());
} else {
value = String.valueOf(entry.getValue());
}
if (key != null && !key.isEmpty()) {
params.append(key).append(value);
}
}
// 组合签名字符串
String signStr = time + nonce + secret + params;
// MD5加密
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(signStr.getBytes());
// 转换为大写的十六进制字符串
StringBuilder result = new StringBuilder();
for (byte b : bytes) {
result.append(String.format("%02X", b));
}
return result.toString();
}
private static String sendPostRequest(String urlStr, Map<String, String> headers, String data) throws Exception {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
StringBuilder response = new StringBuilder();
try {
// 设置请求方法和超时时间
conn.setRequestMethod("POST");
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
// 设置请求头
for (Map.Entry<String, String> entry : headers.entrySet()) {
conn.setRequestProperty(entry.getKey(), entry.getValue());
}
// 启用输入输出流
conn.setDoOutput(true);
conn.setDoInput(true);
// 写入请求体
try (OutputStream os = conn.getOutputStream()) {
byte[] input = data.getBytes("utf-8"); // 直接使用data,不再次序列化
os.write(input, 0, input.length);
}
// 获取响应码
int responseCode = conn.getResponseCode();
// 如果响应码不是成功的范围,抛出异常
if (responseCode < 200 || responseCode >= 300) {
throw new IOException("HTTP Request Failed with Error Code: " + responseCode + "\nResponse: " + response.toString());
}
// 读取响应内容
try (BufferedReader br = new BufferedReader(new InputStreamReader( conn.getInputStream(), "utf-8"))) {
String responseLine;
while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
}
} catch (Exception e) {
System.err.println("Request failed: " + e.getMessage());
if (response.length() > 0) {
System.err.println("Error response: " + response.toString());
}
throw e;
} finally {
if (conn != null) {
conn.disconnect();
}
}
return response.toString();
}
}