支付回调失踪的第一夜

接了个电商客户,要求走易支付的微信扫码。前半夜顺得像德芙——申请商户、下载密钥、填回调地址,照着文档十分钟完事。一切到测试环境,扫码付钱,微信扣款成功,商户后台订单还是“待付款”。

回调丢了。

当时我没当回事。干支付的都知道,回调延迟三五分钟算正常。我泡了杯茶,点根烟,准备等它自己进来。

等了十分钟,日志文件比我的脸还干净。

我差点把服务器给重装了

那是不是回调URL填错了?又钻进易支付商户管理后台,域名、端口、路径一遍遍对,一个字符都没差。我甚至把回调地址改成纯IP,照样石沉大海。翻了一圈文档都没找到这叫什么毛病。

我开始怀疑Nginx。是不是rewrite规则把POST吃掉了?还是location配置没透传?access.log里连个POST的影子都没有,说明请求压根没到应用层。防火墙日志也干净。逻辑上只剩一种可能:易支付没发。

给官方发工单,客服秒贴了张截图:“回调已发送,目的IP x.x.x.x,时间戳14:22:31”。人家发了,我这边没接住。

我干了件蠢事。把整套环境克隆到本地,用内网穿透搭了个临时回调地址,去商户后台把地址一换,重新支付。五秒钟,回调精准命中。当时我就懵了,同样的代码,同样的配置,本地能通,生产就哑火,这不科学。

证书链的暗坑

直到瞥见Nginx error.log里躺着一行:“SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown”。证书不认识?可浏览器打开明明是绿锁。

查完想扇自己。服务器上只配了站点证书,没配中间CA证书链。浏览器会自动补全链,但易支付回调服务器用的OpenSSL版本偏老,不认这种半截子证书,直接拒掉握手。合并完整证书链,重启Nginx,滴滴一声,回调终于撞进日志。

验签失败活不过的真正凶手

我开始怀疑文档里的“密钥为商户密钥的MD5值”这句话有歧义。是不是密钥要做成32位小写再参与签名?试了,不对。是不是参数排序要排除sign字段?文档说排除,我早就排了。把官方sdk翻来覆去看,跟我的逻辑没有任何区别。

猜到了吗?

那个密钥文件,下载之后我用记事本打开看过一眼,可能随手按了下回车再保存。就这一个动作,文件末尾多了一个换行符。代码里用file_get_contents读进来,末尾藏着0x0a,算出来的MD5自然跟平台端的不一致。而官方原始文件末尾是没有换行的。

// 加这一行就能救命
$key = trim(file_get_contents('/path/key.pem'));

如果再遇到,我会先看这里

还有一次要给客户备条备用通道,问客服易支付支持哪些支付方式,对面飞快地报:微信、支付宝、云闪付、QQ钱包、网银。我特意测了QQ钱包,稳定性明显不如微信,后来老老实实切回去了。所以“支持”二字,只是说接口通了,不代表每个通道都好用。

论易支付口碑,圈子里属于那种“上限看人,下限看脸”的类型。配置严丝合缝,它稳得像块铁;但凡漏了点鸡毛蒜皮,它就跟你闹脾气。别指望它有多智能的容错机制,门锁得自己拧紧。

如果再有人问我易支付靠谱吗,我会说:你先把证书链补齐,再把密钥文件末尾的不可见字符剃干净,它大概率是靠谱的。如果你也遇到回调不来,别学我先查网络、查框架,直接看Nginx ssl error.log,再数一下密钥文件字节数是不是多了一两个。

听说新版本商户后台会上线密钥文件校验,如果上传的pem末尾有不可见字符会自动弹提示。是新接入的留意下这个特性,或许能替你省掉我这半夜的咖啡钱。至于以后接口规范会不会再变,谁知道呢,我反正把trim写进脚手架模板了。