简要描述:
通过自定义签名方法,调用开放平台接口
一、生成参数字符串
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(); } }