BMOP的API是基于HTTP协议来调用的,开发者(ISV)可以直接使用BMOP提供的官方SDK(支持JAVA,PHP,.NET语言,包含了请求的封装,签名加密,响应解释,性能优化等)来调用,也可以根据力方开放平台的协议来封装HTTP请求进行调用,以下主要是针对自行封装HTTP请求进行API调用的原理进行详细解说。
根据力方开放平台API调用协议:封装参数 > 生成签名 > 拼装HTTP请求 > 封装参数 > 发起HTTP请求 > 获取HTTP响应 > 解释json报文,以下是大致的调用示意图:
调用环境 | 入口地址(HTTP) | 入口地址(HTTPS) |
正式测试环境 | http://api.bm001.com/api | https://api.bm001.com/api |
正式环境 | http://api.bm001.com/api | https://api.bm001.com/api |
系统级参数说明 | |||
名称 | 类型 | 是否必须 | 描述 |
method | string | 必须 | API接口方法名称 |
v | string | 必须 | 接口版本号,可选值:1.1 |
sign | string | 必须 | API输入参数的数字签名,签名算法参照下面的介绍 |
access_token | string | 可选 | 用户登录授权成功以后,力方开放平台会颁发给应用的授权信息access_token(接口访问令牌),API是需要需要传入此参数,请参考各API的用户授权类型。 |
timestamp | number | 必须 | 请求时间戳,时区为GMT+8(北京时间),格式:"yyyy-MM-dd HH:mm:ss", 例如"2012-12-20 10:20:35",力方API服务器允许的时间误差在10分钟。 |
业务级参数是每个API本身业务所需要的参数,每个API的业务级参数请参考API文档说明,下面以bm.elife.recharge.mobile.getItemInfo(话费充值-查询单个话费直充商品)。
应用级参数说明 | |||
名称 | 类型 | 是否必须 | 描述 |
mobileNo | number | 必须 | 需要充值的手机号码 |
rechargeAmount | number | 必须 | 正整数,例如20、50、100等面值 |
为了防止API调用过程中被黑客恶意篡改,调用任何一个API都需要携带数字签名,力方开放平台服务端会对签名进行校验,签名不合法的请求将会被拒绝,力方开放平台目前支持的签名算法为SHA1,签名的大致过程如下:
说明:SHA1为安全哈希算法,主要用于数字签名标准(DSS)中的签名算法(DSA),SHA1会产生一个160位的消息摘要,用16进制表示,一个16进制的字符能表示4个位,所以签名后的长度固定为40个16进制字符。
JAVA签名示例代码(其他语言的签名示例请参考力方开放平台官方SDK源码)package com.qianmi.util; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.MessageDigest; import java.util.*; /** * Created by QianMi */ public class SignUtil { public static String sha1(String str) throws IOException { return byte2hex(getSHA1Digest(str)); } private static byte[] getSHA1Digest(String data) throws IOException { byte[] bytes; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); bytes = md.digest(data.getBytes("utf-8")); } catch (GeneralSecurityException gse) { throw new IOException(gse); } return bytes; } private static String byte2hex(byte[] bytes) { StringBuilder sign = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { String hex = Integer.toHexString(bytes[i] & 0xFF); if (hex.length() == 1) { sign.append("0"); } sign.append(hex.toUpperCase()); } return sign.toString(); } public static String sign(Map<String, String> param, String secret) throws IOException { if (param == null) { return null; } StringBuilder sb = new StringBuilder(); List<String> paramNames = new ArrayList<>(param.size()); paramNames.addAll(param.keySet()); Collections.sort(paramNames); sb.append(secret); for (String paramName : paramNames) { sb.append(paramName).append(param.get(paramName)); } sb.append(secret); return sha1(sb.toString()); } public static void main(String[] args) throws IOException { Map<String, String> param = new HashMap<>(); param.put("access_token", "7466bdfc5f79a7fe1defd9a5880a4b84"); param.put("v", "1.1"); param.put("method", "bm.elife.recharge.mobile.getItemInfo"); param.put("timestamp", "1428488009985"); param.put("mobileNo", "13888888888"); param.put("rechargeAmount", "100"); System.out.println(sign(param, "test")); } }
{ status: 1, message: null, data: { itemId: "1414504", inPrice: "110.000", numberChoice: "1-10", province: "江苏", city: "南京", operator: "移动" } }