签名调用

简要描述:

  • 通过自定义签名方法,调用开放平台接口

一、生成参数字符串

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();
    }
}