TimothyQiu's Blog

keep it simple stupid

No Comments

经常追番的童鞋应该对日语的「喫茶店きっさてん」一词不陌生,它就是咖啡馆、茶店的意思。因为「吸烟」是「喫煙きつえん」,以及小学语文老师「秀才不识字,念半边」的教诲,我一直把「喫」字读作 qì。最近偶尔发现「喫」字在普通话中应该念 chī,感觉打开了新世界的大门。

阅读剩余部分...

使用支付宝「移动支付」同步通知时遇到的问题与吐槽

No Comments

移动支付」是支付宝推出的针对手机移动支付的服务。虽然支付宝现在建议新商户转用「App 支付」接口了,但是一些较早接入的 App 仍旧在使用这个服务,比如鄙厂的智能证件照 ;-)

各大支付服务的套路其实都是一样的,无论网页还是 App:

  1. 服务器为支付所需数据签名
  2. 客户端使用签名后的数据调起支付服务
  3. 用户支付成功后,客户端获得支付结果同步通知,服务器获得异步通知回调

显然支付状态应以服务器获得的异步通知为准,不过某些情况下,客户端可能会有在先检查一下本地的支付结果有效性的需求。

前些天在 Sentry 里收到了错误报告,原因是校验客户端获得的同步通知结果时,发生了「被校内容格式异常」的错误。初以为是有人故意修改了客户端在捣乱,检查请求内容才发现,原来是支付宝(不知为何)本次发来的同步通知内容使用了不同以往的格式:

partner="2088101568358171"&seller_id="xxx@alipay.com"&out_trade_no="0819145412-6177"&subject="测试"&body="测试测试"&total_fee="0.01"&notify_url="http://notify.msp.hk/notify.htm"&service="mobile.securitypay.pay"&payment_type="1"&_input_charset="utf-8"&it_b_pay="30m"&success="true"&sign_type="RSA"&sign="hkFZr+zE9499nuqDNLZEF7W75RFFPsly876QuRSeN8WMaUgcdR00IKy5ZyBJ4eldhoJ/2zghqrD4E2G2mNjs3aE+HCLiBXrPDNdLKCZgSOIqmv46TfPTEqopYfhs+o5fZzXxt34fwdrzN4mX6S13cr3UwmEV4L3Ffir/02RBVtU=";extendInfo="doNotExit":true,"isDisplayResult":true

末尾前无古人后无来者地加了个分号,然后以奇怪的格式引入了 extendInfoisDisplayResult 两个字段。这是文档中从来没有提过会发生的事情。

原本通过文档中字段说明及例子,我们可能还觉得返回的支付结果就是用的 HTTP Query String 格式,而且支付结果去除涉及签名的 signsign_type 相关键值对后可以直接用来验证签名。收到这回这么一条回调,就都不成立了。

所幸原先为了偷懒没有以 HTTP Query String 的格式解析支付结果,而是直接用正则表达式 ^(.+)&sign_type="RSA"&sign="(.+)"$ 从中提取待签名字符串及签名本身。(偷懒之处在于:因为如果解析以后,按照支付宝的签名规则,我还得再把它们重新排序;而解析前的键值对本身已经是排过序的了。)

但不幸的是,这个正则表达式认为 sign="xxxx" 后不应该有任何多余数据。于是便有了「被校内容格式异常」。

反思及吐槽

前两天刚在知乎大言不惭地在回答里说很多程序员不肯看文档、凭直觉掩耳盗铃地写代码,结果这就立马变成自我吐槽了 ;-(

其实仔细看支付宝的文档的话,关于同步通知中的支付结果和签名,是这样说的:

result:本次操作返回的结果数据。其中:&success="true"&sign_type="RSA"&sign="xxx"之前的部分为商户的原始数据。success用来标识本次支付结果。sign="xxx"为支付宝对本次支付结果的签名(加签内容为:案例中原始数据&支付结果,……)

首先,你看文档里确实并没有保证支付结果数据始终以 sign="xxx" 结尾。我在正则表达式里作出那样的假设,是基于例子退出的假设,但这其实是个高中数学「充要条件」的问题。

其次,我那偷懒利用结果数据中「已排序」特性的操作,虽然目前并没有什么问题,但其实也是有风险的。因为文档里并没有保证它的有序性。

所以嘛,我错了,我应该好好看文档的……

以上,真是有意义的一天呐~

自旋锁、互斥器、条件变量及读写锁

No Comments

这是上个礼拜难得没有犯懒,为知乎的问题《如何理解互斥锁,条件锁,读写锁以及自旋锁?》写的一个比较长的回答。

阅读剩余部分...

std::error_code 和它的朋友们

No Comments

前几天看 API 文档时候遇到了 std::error_code 这个东西,当时以为是 errno 的 Alias,后续查阅文档才发现并没有那么简单。

阅读剩余部分...

从 feedly 投向 inoreader

No Comments

当年 Google Reader 拜拜后,我也陆续尝试了不少国内国外的替代品。当时选择了相对不错的 feedly,但因为不像 GR 一样存在感强烈,常常忘掉它的存在。最近整理阅读渠道,又把 feedly 拾起来,就感觉到了 feedly 的不足。

阅读剩余部分...