什么是 HTTP 访问服务能力?HTTP 访问能力是旨在让用户可以通过简单的 HTTP 请求方式来访问用户部署在云开发环境里的云上资源,例如云函数、静态网站托管以及云托管服务等云上资源。可以通过资源绑定的方式,将云开发环境里的云上资源绑定到某个特定的 URL 上,之后只需向该 URL 发送简单的 HTTP 请求即可访问到云上资源,从而避免了使用各种语言的 SDK 带来的繁琐以及语言版本特性等诸多原因带来的问题。
了解了以上内容后,接下来详细介绍通过 HTTP 访问服务和云函数这两个现有能力来快速生成所需要的通知回调地址。
一、步骤1:创建云函数
如上文所述,由于服务要求填入统一下单和申请退款两个通知回调地址,所以需要创建两个云函数。进入云开发环境后,在左侧导航栏选择云函数,在右侧云函数页面中单击新建云函数,开始新建云函数。
如下所示,创建两个云函数,分别为:
·order:用于处理统一下单通知回调。
·refund:用于处理申请退款通知回调。
云函数代码先使用默认写好的示例代码即可,填写好云函数名称后直接单击下一步,确定后即可完成创建。
二、步骤2:绑定 HTTP 访问路径
创建好云函数后,接下来开始给云函数绑定 HTTP 访问路径。登录云开发控制台,单击左侧导航栏,选择环境管理 > HTTP 访问服务,并单击右侧页面中的添加路由,开始新建访问路径,如下:
首先,将处理统一下单通知回调的云函数 order 的 HTTP 触发路径设置为 /order,并单击确定,如下:
同理,将处理申请退款通知回调的云函数 refund 的 HTTP 触发路径设置为 /refund,并单击确定。这样就创建好了两个云函数对应的两条 HTTP 访问路径。
三、步骤3:测试访问服务是否可用
服务绑定完成之后,需要简单测试下服务是否已经可用。单击 HTTP 访问服务中的触发路径,此时浏览器会打开一个这样的地址:https://xxx.ap-shanghai.app.tcloudbase.com/order 和 https://xxx.ap-shanghai.app.tcloudbase.com/refund 。这两个地址即是所需要的统一下单和申请退款的通知回调地址。当页面显示响应内容时,表示服务已经可用,如果页面显示报错,则表示服务正在启动,大概 5 分钟后重试即可。
四、2. 使用回调地址
如上文所述,准备好的两个用于处理统一下单和申请退款的通知回调地址,分别是:
·统一下单:https://xxx.ap-shanghai.app.tcloudbase.com/order
·申请退款:https://xxx.ap-shanghai.app.tcloudbase.com/refund
将其填入如下位置即可。
当在小程序里调用微信支付完成下单或申请退款操作后,微信支付会以请求回调通知地址的方式同步支付结果,接下来,看看如何在云函数里处理微信支付的请求。
五、步骤1:处理统一下单通知回调请求
当微信支付回调 https://xxx.ap-shanghai.app.tcloudbase.com/order 地址的时候,会将请求返回给该地址绑定的云函数里面,所以需要在云函数里处理回调请求。
在云开发控制台中打开 order 云函数,进入到云函数代码编辑页面,填入以下代码:
'use strict';const crypto = require("crypto")exports.main = async (event, context) => { /** * 从event.body里获取微信支付请求通知回调时携带的参数,参数说明详见 * https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html#%E9%80%9A%E7%9F%A5%E5%8F%82%E6%95%B0 */ const { id, // 通知的唯一ID create_time, //通知创建的时间 resource_type, // 通知的资源数据类型 event_type, // 通知的类型 summary, // 回调摘要 resource, // 通知资源数据 } = JSON.parse(event.body) const key = `xxxxxx`; // APIv3 密钥 const nonce = resource.nonce; // 加密使用的随机串 const associated_data = resource.associated_data; // 加密用的附加数据 let ciphertext = resource.ciphertext; // 加密体 ciphertext = Buffer.from(ciphertext, 'base64'); const authTag = ciphertext.slice(ciphertext.length – 16); const data = ciphertext.slice(0, ciphertext.length – 16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce); decipher.setAuthTag(authTag); decipher.setAAD(Buffer.from(associated_data)); const decoded = decipher.update(data, null, 'utf8'); decipher.final(); const decodedData = JSON.parse(decoded); //解密后的数据 console.log('解密后的数据', decodedData) return null};
可以从 event.body 里获取微信支付请求通知回调时携带的参数,参数示例如下:
{ id: "a3fc0826-1b9a-5f21-b918-4abb937468fc", create_time: "2023-10-18T20:46:21+08:00", resource_type: "encrypt-resource", event_type: "TRANSACTION.SUCCESS", summary: "支付成功", resource: { original_type: "transaction", algorithm: "AEAD_AES_256_GCM", ciphertext:"….", associated_data: "transaction", nonce: "9pZlUiqMsfi2", },}
参数说明请参见 微信支付-支付通知文档。其中携带参数列表中的 resource 字段里包含了下单的业务资源,这个字段内容是加密的,需要按照微信支付的规则进行解密,解密后数据示例如下:
{ mchid: '161375xxxx', appid: 'wx480c825d7xxxxxx', out_trade_no: 'weda_2023-10-18-10117', transaction_id: '420000199120231018419562xxxx', trade_type: 'JSAPI', trade_state: 'SUCCESS', trade_state_desc: '支付成功', bank_type: 'OTHERS', attach: '', success_time: '2023-10-18T20:46:21+08:00', payer: { openid: '…' }, amount: { total: 1, payer_total: 1, currency: 'CNY', payer_currency: 'CNY' }}
字段说明请参见 支付通知文档。
六、步骤2:处理申请退款通知回调请求
同理,在 refund 云函数里处理申请退款通知回调请求,在云开发控制台中打开 refund 云函数,进入到云函数代码编辑页面,仍旧填入以下代码:
'use strict';const crypto = require("crypto")exports.main = async (event, context) => { /** * 从event.body里获取微信支付请求通知回调时携带的参数,参数说明详见 * https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/payment-notice.html#%E9%80%9A%E7%9F%A5%E5%8F%82%E6%95%B0 */ const { id, // 通知的唯一ID create_time, //通知创建的时间 resource_type, // 通知的资源数据类型 event_type, // 通知的类型 summary, // 回调摘要 resource, // 通知资源数据 } = JSON.parse(event.body) const key = `xxxxxx`; // APIv3 密钥 const nonce = resource.nonce; // 加密使用的随机串 const associated_data = resource.associated_data; // 加密用的附加数据 let ciphertext = resource.ciphertext; // 加密体 ciphertext = Buffer.from(ciphertext, 'base64'); const authTag = ciphertext.slice(ciphertext.length – 16); const data = ciphertext.slice(0, ciphertext.length – 16); const decipher = crypto.createDecipheriv('aes-256-gcm', key, nonce); decipher.setAuthTag(authTag); decipher.setAAD(Buffer.from(associated_data)); const decoded = decipher.update(data, null, 'utf8'); decipher.final(); const decodedData = JSON.parse(decoded); //解密后的数据 console.log('解密后的数据', decodedData) return null};
从 event.body 里获取微信支付请求通知回调时携带的参数,参数示例如下:
{ id: "e59bba96-1920-56f4-aac9-287eacde4510", create_time: "2023-10-18T21:12:51+08:00", resource_type: "encrypt-resource", event_type: "REFUND.SUCCESS", summary: "退款成功", resource: { original_type: "refund", algorithm: "AEAD_AES_256_GCM", ciphertext: "…", associated_data: "refund", nonce: "MHDDHcJ3FuvG", },}
参数说明请参见 退款结果通知。其中携带参数列表中的 resource 字段里包含了下单的业务资源,这个字段内容是加密的,需要按照微信支付的规则进行解密,解密后数据示例如下:
{ mchid: '161375xxxx', out_trade_no: 'weda_2023-10-18-10117', transaction_id: '42000019912023101841956xxxx', out_refund_no: 'weda_2023-10-18-10117', refund_id: '50302107462023101827007675043', refund_status: 'SUCCESS', success_time: '2023-10-18T21:12:51+08:00', amount: { total: 1, refund: 1, payer_total: 1, payer_refund: 1 }, user_received_account: '支付用户零钱'}
字段说明请参见 退款结果通知。
七、总结
以上,就是使用 HTTP 访问服务能力快速生成通知回调地址的所有步骤,接下来,就可以在云函数里根据微信支付的处理状态来编写业务代码,对业务进行下一步处理,如需操作微搭数据源信息,请参见 管理端-数据源 开发文档。