# 第三方订单回调

接口地址:http://gateway--cnki--net--https.cnki.mdjsf.utuvpn.utuedu.com:9000/openx/jssdk/order/v1/callback

请求方式:POST

请求数据类型:application/json

响应数据类型:*/*

接口描述: 第三方订单回调

请求示例:

{
    "appId": "1731****16030",
    "openId": "k8FYCJDK1JjB****C3rkI83cY9",
    "payTime": "2025-08-12 12:30:00",
    "payType": "WECHAT",
    "payExtra": "M6/spyB1h5Ijm/wOjeECuHne********kcBNuQ=="
}

请求参数:

参数名称 参数说明 请求类型 是否必须 数据类型
  appId 第三方应用在研学开放平台申请的应用ID body true string
  openId 第三方平台获取研学开放平台用户信息返回的用户标识,详见:知网研学开放平台文档-认证中心-根据Token获取用户信息 (opens new window) body true string
  payExtra 支付主体信息,包含订单详细信息的加密字符串,支付核心数据,生成方式见下文备注。 body true string
  payTime 支付时间,格式 yyyy-MM-dd HH:mm:ss body true string
  payType 支付方式 ,WECAHT 代表微信,ALIPAY 代表支付宝,OTHER代表其他 body true string
Authorization 接口请求的凭证,获取方式详见:知网研学开放平台文档-认证中心-客户端模式获取JWT (opens new window) header true string
Content-Type application/json header true string

注意事项:Authorization参数是携带在请求的header中,格式示例(注意Bearer 后有空格):

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCaWF...

备注:支付主体payExtra生成规则如下:

order_noproduct_idproduct_nametotal_feeduration_days五个支付主体信息使用键值对的格式(即key1=value1&key2=value2…)拼接成字符串,结果类似:order_no=dsfzf20250907&product_id=jakhdjskadjkh23sdsf93s&product_name=测试月卡&total_fee=20.13&duration_days=30,之后对拼接后的字符串进行AES加密。

字段 释义 类型 是否必须
order_no 支付订单编号 String
product_id 商品ID String
product_name 商品名称 String
total_fee 总支付费用,字符串类型的数字,精度为小数点后两位,比如29.99 String
duration_days 权益持续时间,字符串类型的正整数,单位天,没有可以传"0" String

加密的示例代码如下(秘钥为开发者在研学开放平台申请的ApiKey):

/**
 * 加密Map
 *
 * @param data 要加密的数据
 * @return 加密后的字符串
 * @throws Exception
 */
public static String encryptMap(Map<String, String> data, String secretKey) throws Exception {
    // 元素排序
    Map<String, String> sortedData = new TreeMap<>(data);
    StringBuilder dataToEncrypt = new StringBuilder();
    for (Map.Entry<String, String> entry : sortedData.entrySet()) {
        dataToEncrypt.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
    }
    // 去掉最后一个多余的&
    if (dataToEncrypt.length() > 0) {
        dataToEncrypt.setLength(dataToEncrypt.length() - 1);
    }
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
    byte[] encryptedBytes = cipher.doFinal(dataToEncrypt.toString().getBytes(StandardCharsets.UTF_8));
    return Base64.getEncoder().encodeToString(encryptedBytes);
}

 /**
     * 解密Map
     *
     * @param encryptedData 加密后的字符串
     * @return 解密后的Map
     * @throws Exception
     */
public static Map<String, String> decrypt(String encryptedData, String secretKey) throws Exception {
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "AES");
    cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
    byte[] decodedBytes = Base64.getDecoder().decode(encryptedData);
    byte[] decryptedBytes = cipher.doFinal(decodedBytes);
    String decryptedString = new String(decryptedBytes, StandardCharsets.UTF_8);

 Map<String, String> decryptedMap = new TreeMap<>();
    String[] pairs = decryptedString.split("&");
 for (String pair : pairs) {
        int idx = pair.indexOf("=");
     if (idx > 0) {
            decryptedMap.put(pair.substring(0, idx), pair.substring(idx + 1));
     }
    }
    return decryptedMap;
}

public static void main(String[] args) {
    Map<String, String> data = new HashMap<>();
    data.put("order_no", "ds****f20250907");
    data.put("product_id", "1741***071581");
    data.put("product_name", "测试月卡");
    data.put("total_fee", "23.22");
    data.put("duration_days", "30");
    try {
        String encrypt = encryptMap(data, "Nmq******H0Rp");
        System.out.println("加密结果:" + encrypt);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

加密算法:AES

工作模式:ECB

填充方式:PKCS5Padding

以上是Java语言实现的加密算法,其它语言加密请保证相同的算法、工作模式、填充方式。

注意编码格式为:UTF_8

请妥善保存应用秘钥ApiKey

响应状态:

状态码 说明
200 OK
500 系统异常!
400505 应用不存在!
400523 xxxx参数不能为空!
400530 时间格式异常!
400531 订单信息解密失败!
400529 三方支付信息缺失!

响应参数:

参数名称 参数说明 类型 schema
code 接口返回状态码 integer(int32) integer(int32)
content 接口返回数据 object
count 接口返回数据条数,用于分页查询 integer(int32) integer(int32)
message 接口返回信息 string
success 接口返回是否成功 boolean
total 接口返回数据条数,用于分页查询 integer(int32) integer(int32)

响应示例:

{
    "success": true,
    "message": "SUCCESS",
    "content": null,
    "count": null,
    "total": null,
    "code": 200
}