目录

服务端开发

服务端支付签名处理

在客户端开发章节提到,对于有服务器的非单机应用,需要在应用的服务端完成支付参数的签名,以保障支付私钥的安全性,本章节介绍如何在服务端完成支付签名方法的开发,至于应用客户端和应用服务器之间的交互接口,由开发者自行实现。

  1. 构造待签名支付参数字串。

    • 将支付参数中需要参与签名的参数(参与签名的参数是指payreq中标识需要签名的参数,值为空<包括null和"">的不参与签名),按参数名的ASCII码的增序排序,若遇到相同首字母,则看第二个字母,以此类推。
    • 排序完成之后,再把所有数组值以“&”字符连接起来。

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

  2. 生成签名值。

    • 将源串使用RSA算法(SHA256WithRSA)进行签名。
    • 将签名后的字符数组经过Base64.encode编码,生成签名值。

    详细代码参见服务端示例代码。

支付回调接口处理

对于无服务器的单机应用,开发者无需关注本章节,有服务器的非单机应用开发者需要实现本章节,以实现支付结果回调的处理。支付回调是用户使用华为支付进行付款成功后,华为支付服务器将回调开发者的服务器通知支付结果。开发者需在华为开发者联盟上申请支付服务时,填入回调URL才可使用本功能,回调URL为开发者的应用服务器对外提供的服务地址。

[h2]回调机制说明

回调重发:若开发者服务器对于支付回调返回结果为非成功响应(返回的result值为非0),将对同一笔订单的回调进行周期性重发。

重发机制:共2天,前3次每20s尝试一次,4-20次每200s尝试一次,之后每3小时尝试一次。

[h2]回调接口协议描述

承载协议

HTTP POST

接口方向

华为支付服务器->商户服务器

接口URL

application/x-www-form-urlencoded

数据格式

请求消息:Content-Type: application/json

响应消息:Content-Type: application/json

数据字符编码格式

UTF-8

  • 请严格按接口定义返回相应的结果码,包括已经明确定义的错误情况。具体结果码请参见回调响应约定。
  • 不允许商户设置IP允许清单用于限制华为侧的出口IP地址。IP允许清单本身并不能提高安全性且会给业务发展带来约束,在消息层面已有更安全的RSA签名机制条件下,没有存在价值。商户不遵守该约定而导致的后果由商户承担。

[h2]回调接口请求参数

URL参数:无

Body参数:见下表

名称

类型

是否必选

描述

result

String(3)

是

支付结果。

  • 0:支付成功
  • 1:退款成功(暂未启用)

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)

否

银行编码-支付通道信息,可选参数。如下情况会进行传递:

  • 参数有具体取值
  • 商户在前台sdk中指定了urlver配置项为“2”

orderTime

String

否

下单时间,格式为yyyy-MM-dd hh:mm:ss。

说明:

该字段仅在urlver为2时返回。

tradeTime

String

否

交易/退款时间,格式为yyyy-MM-dd hh:mm:ss。

说明:

该字段仅在urlver为2时返回。

accessMode

String

否

接入方式,取值如下:

  • -1:未知设备
  • 0:手机
  • 1:PC-Web
  • 2:Mobile-Web
  • 3:TV(包括机顶盒)
  • 4:pad
  • 5:watch
  • 6:kid watch
  • 7:PC simulator
  • 8:mobile tv
  • 9:glass
  • 10:ear phone
  • 11:car
  • 12:kid pad
说明:

该字段仅在urlver为2时返回。

spending

String

否

渠道开销,保留两位小数,单位元。

说明:

该字段仅在urlver为2时返回。

extReserved

String

否

商户侧保留信息,原样返回商户调用支付SDK输入的保留信息。未输入时,不返回。

说明:
  • 考虑到自选参数格式多样化,本参数在“utf-8” urlencode后发送。
  • Java中request的getParameter()方法会隐含进行urldecode。

sysReserved

String

否

系统保留信息。

  • 微信:支付该笔订单的用户ID。
  • 定制支付:透传定制支付系统的取值。
  • 华为充值卡:传递华为充值卡的卡号。类型为JSON字符串,用于传递华为充值卡的卡号、是否赠送标记,参数名为“cardSeq”、“appCardType”,多个卡号使用@符号分割。
  • 其他:不出现。
说明:
  1. 考虑到自选参数格式多样化,本参数在“utf-8” urlencode后发送。
  2. Java中request的getParameter()方法会隐含进行urldecode。

signType

String

是

签名类型,不参与签名。

  • 没有传递signType或者signType值为RSA,表示使用SHA1WithRSA算法。
  • signType值为RSA256,表示使用SHA256WithRSA算法。

sign

String

是

RSA签名。

说明:
  • sign、signType以及回调中不存在的参数不参与签名,回调中存在的参数,即使值为空(value=null或者“”)也需要参与签名,签名验证content的格式如下:“parametername1=value1 || parametername2=value2"。
  • 考虑到自选参数格式多样化,本参数在“utf-8”urlencode后发送。
  • Java中request的getParameter()方法会隐含进行urldecode。

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处理,其余参数不需要处理。

[h2]回调响应约定

http返回码:200

Body参数:

名称

类型

描述

是否必选

result

int

操作结果。

  • 0:成功
  • 1:验签失败
  • 2:超时
  • 3:业务信息错误,比如订单不存在
  • 94:系统错误
  • 95:IO错误
  • 96:错误的URL
  • 97:错误的响应
  • 98:参数错误
  • 99:其他错误

是

  • 对于重复的订单,要求返回0。
  • 请严格按定义的结果码返回,包括各种已经明确定义的错误码。
  • 商户收到通知消息时,在完成最小必要处理后,要立即返回响应,避免超时。

开发步骤

应用服务器的开发者需要完成对支付回调中支付结果的验签,验签方法参见服务端支付签名处理,并更新自己服务端的支付结果,此处逻辑应用自行实现,部分代码请参见服务端示例代码。