在客户端开发章节提到,对于有服务器的非单机应用,需要在应用的服务端完成支付参数的签名,以保障支付私钥的安全性,本章节介绍如何在服务端完成支付签名方法的开发,至于应用客户端和应用服务器之间的交互接口,由开发者自行实现。
例如:BankId=JUNNETNET&amount=2.00&ifyTime=1353317037173&orderId=918370122485714G&payType=2&productName=珍珠项链&requestId=1352286825177&result=0&userName=lilan
Java代码实现示例,以作参考:
/**
* 除了sign、signType以及回调中不存在的参数不参与签名,将其他的所有请求参数按照key的ASCII码进行升序排列,然后拼接成
* key1=value1&key2=value2&key3=value3.....
* 如果参数为null或空,写成key1=&key2=value2&key3=value3
* @param params 上面获取的所有请求参数
* @return 用于签名校验的字符串
*/
public static String getSignData(Map<String, Object> params)
{
StringBuffer content = new StringBuffer();
// 按照key做排序
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys);
for (int i = 0; i < keys.size(); i++)
{
String key = (String) keys.get(i);
// 如果是sign字段,不作为签名校验参数
if ("sign".equals(key))
{
continue;
}
// 如果是signType字段,不作为签名校验参数
if ("signType".equals(key))
{
continue;
}
String value = (String) params.get(key);
if (value != null)
{
content.append((i == 0 ? "" : "&") + key + "=" + value);
}
else
// 如果value为null,则写成:key=&key1=value1
{
content.append((i == 0 ? "" : "&") + key + "=");
}
}
return content.toString();
} 详细代码参见服务端示例代码。
对于无服务器的单机应用,开发者无需关注本章节,有服务器的非单机应用开发者需要实现本章节,以实现支付结果回调的处理。支付回调是用户使用华为支付进行付款成功后,华为支付服务器将回调开发者的服务器通知支付结果。开发者需在华为开发者联盟上申请支付服务时,填入回调URL才可使用本功能,回调URL为开发者的应用服务器对外提供的服务地址。
回调重发:若开发者服务器对于支付回调返回结果为非成功响应(返回的result值为非0),将对同一笔订单的回调进行周期性重发。
重发机制:共2天,前3次每20s尝试一次,4-20次每200s尝试一次,之后每3小时尝试一次。
| 承载协议 | HTTP POST |
|---|---|
| 接口方向 | 华为支付服务器->商户服务器 |
| 接口URL | application/x-www-form-urlencoded |
| 数据格式 | 请求消息:Content-Type: application/json 响应消息:Content-Type: application/json |
| 数据字符编码格式 | UTF-8 |
URL参数:无
Body参数:见下表
| 名称 | 类型 | 是否必选 | 描述 |
|---|---|---|---|
| result | String(3) | 是 | 支付结果。
|
| userName | String | 是 | 商户名称,开发者注册的公司名。 |
| productName | String(100) | 是 | 商品名称。 |
| payType | int | 是 | 支付类型,取值请参见payType说明。 |
| amount | String(10) | 是 | 商品支付金额(保留2位小数, 例如:20.00)。 说明: 退款通知下,为退款金额,目前仅支持全额退款。 |
| orderId | String(50) | 是 | 华为支付平台订单号。 |
| notifyTime | String(15) | 是 | 通知时间(自1970年1月1日0时起的毫秒数)。 |
| requestId | String(50) | 是 | 商户订单号。 来源:开发者应用在支付前生成,用来唯一标识一次支付请求。 该字段由字母和数字组成,必须在商户内唯一,用于唯一标识一个商户订单。 |
| bankId | String(50) | 否 | 银行编码-支付通道信息,可选参数。如下情况会进行传递:
|
| orderTime | String | 否 | 下单时间,格式为yyyy-MM-dd hh:mm:ss。 说明: 该字段仅在urlver为2时返回。 |
| tradeTime | String | 否 | 交易/退款时间,格式为yyyy-MM-dd hh:mm:ss。 说明: 该字段仅在urlver为2时返回。 |
| accessMode | String | 否 | 接入方式,取值如下:
说明: 该字段仅在urlver为2时返回。 |
| spending | String | 否 | 渠道开销,保留两位小数,单位元。 说明: 该字段仅在urlver为2时返回。 |
| extReserved | String | 否 | 商户侧保留信息,原样返回商户调用支付SDK输入的保留信息。未输入时,不返回。 说明:
|
| sysReserved | String | 否 | 系统保留信息。
说明:
|
| signType | String | 是 | 签名类型,不参与签名。
|
| sign | String | 是 | RSA签名。 说明:
|
Java中对本接口参数的处理建议:
本接口采用的是application/x-www-form-urlencoded格式,会在http层进行编码,同时接收端会自动解码。建议通过如下方法获得的get参数串,也就是华为支付服务器发送的原始信息。而原始信息是没有urlencode的,验签也是需要使用原始内容参与的。而使用request.getParameter()会隐含进行urldecode,在部分情况下可能无法正确获取原始参数信息,比如参数取值中如果包含“%”等特殊符号。
参考代码如下:
InputStream stream = request.getInputStream(); InputStreamReader isr = new InputStreamReader(stream); BufferedReader br = new BufferedReader(isr); String str = br.readLine();
采用如上方法获取参数时,对于sign、sysReserved和extReserved参数需要进行urldecode处理,其余参数不需要处理。