Skip to main content
  1. Posts/

PayPal 即时支付通知(Instant Payment Notification, IPN)实践 ✨

1 分钟
如需使用 IPN 接口,开发者账户必须是企业账户。

对开发者而言,支付收款永远是绕不过去的问题。 网络收款基本两大类。

  • 平台支持。移动平台开发者比较幸运,主流的App Store和Google Play都直接提供了支付服务,对于一次性付费购买问题,开发者无需考虑收款,平台代收然后进行结算(平台按比例抽成)。
  • 自建收款渠道。这涉及的问题就复杂多了。由于地区政策的差异,不同地区需要区别对待,往往需要根据需求封装多种支付方式。中国大陆,微信支付宝都是非常成熟和便捷的方案,集成并不难。 如果是其他地区,则可以考虑使用 PayPal。PayPal不是费率最低的方案,但是考虑到国际金融的复杂性,PayPal无疑是小额收款的最佳方案。

什么是 IPN? #

IPN是 Instant Payment Notification(即时支付通知)的缩写。简而言之,如果我们在PayPal系统中配置了通知接口,用户转账后该接口将收到调用请求,之后程序需要做的是在接口中处理购买逻辑,发放购买权益。

调用flow示意图
官方使用文档

IPNListener接口配置可以是全局的,也可以是针对单个按钮的。我并没有全局配置,而只是在 Buy Now 按钮中配置了回调方法。

SDK #

官方提供了多种语言的调用示例

  • 多语言综合版本
  • Java PayPal官方提供了一个仓库 merchant-sdk-java ,这是一个更详细的java版本封装,其他语言可以用类似merchant-sdk-*的方式来检索。

一些需要特别注意的问题 #

接口超时问题 #

如果服务器在中国大陆,超时风险比较大。也许是因为中国大陆的国际出口信道非常拥堵或者是PayPal的服务SLA比较差,超时是家常便饭。

回调过来后的反向validate经常需要几百毫秒到几十秒不等。

这里建议在IPNListener中减少直接写表操作,而是把数据放到队列中,尽可能避免PayPal的回调超时。否则,就要补偿了,徒增烦恼。

编码问题 #

对于中国大陆的 PayPal 商户,默认的编码是gb2312,不清楚世界其他地区是否有差异。gb2312包含了足够丰富的字符集,适用简体中文、英语、西欧语言等。 缺少了繁体中文,如果有繁体中文用户那就是大问题,需要改成utf8。修改PayPal字符编码

注意这里可能存在与编程语言使用编码不匹配问题。

就Java而言,String类使用的具体是什么编码,和jvm的设置以及系统默认字符集有关。中国用户通常是utf8。如果我们不改PayPal字符集,发送给PayPal进行validate的字符串用的utf8,声明的是gb2312(默认),就会验证失败。

改完字符集后,我们还需要在validate的参数里声明我们用的是utf8。Java版本示例:

 Map<String, String> configurationMap = new HashMap<>();
// Endpoints are varied depending on whether sandbox OR live is chosen for mode
configurationMap.put("mode", paypalMode);
//https://www.paypal.com/cgi-bin/customerprofileweb?cmd=_profile-language-encoding
//https://github.com/paypal/ipn-code-samples/issues/108
configurationMap.put("charset", "utf-8");
IPNMessage ipnListener = new IPNMessage(request, configurationMap);

Reference #

  1. PayPal Github
  2. PayPal Developer IPN
  3. PayPal Change Profile Encoding
  4. GB2312 编码内容