PaymentRequest API 是一种跨浏览器的标准 API,主要的目的是以浏览器充当中介,尽可能标准化支付通信的流程。 ?
整个流程主要是创建 PaymentRequest,将购买货物的详细信息传递给浏览器,在 UI 层面显示支付的 UI,用户填入支付信息或从缓存中一键填充并确认支付。
他的最大的优势是信用卡、收货地址等支付信息都统一存储在浏览器,如果网站都能够使用该 API,那么就不再需要重复填写支付信息。
⚠️ 使用 PaymentRequest 非常简单,但由于兼容性问题,目前不要在生产环境中使用,API 层面亦会有可能改动。
创建 PaymentRequest 实例
第一步是通过调用 PaymentRequest 构造函数创建一个 PaymentRequest 对象
构造函数需要三个参数分别是 methodData、details 和可选的 options
methodData 支付方式
首先需要设定支付方式,传入卖家支持的支付手段,如 visa 或 mastercard 等信用卡或其他方式:
methodData 是一个数组,数组中每一项应为一个对象,对象内包含两个属性:
-
supportedMethods
付款方式识别符 -
data
额外信息-
supportedNetworks
支付网络
-
supportedMethods 需要填写 付款方式识别符,一般填写 basic-card
,也可填写 url 的识别符如:
如果是 google pay url 付款识别符,那么调用的时候长这样:
这里以 basic-card 为例,那么 data 属性则需要填写一些额外的信息,如果是 basic-card 方式,那么还可以选择配置 supportedNetworks
,这个选项指定了 card networks
card networks 是一个数组,如支持 visa、mastercard 等
['visa', 'mastercard', 'amex', 'jcb', 'diners', 'discover', 'mir', 'unionpay']
什么是 card networks 见这篇文章:https://www.cardinalcommerce....
根据规范,我们编写以下代码 ?
const methodData = [{
supportedMethods: 'basic-card',
data: {
supportedNetworks: ['visa', 'mastercard', 'amex', 'jcb', 'diners', 'discover', 'mir', 'unionpay']
}
}]
在调用的时候长这样:
另外,Apple Pay 也支持该特性,详细见文档:https://webkit.org/blog/8182/...
details 交易详情
details 保存的是交易详情,主要有以下字段:
-
total
需要支付的总额 -
id
交易 ID,如果不填写浏览器自动生成 -
displayItems
主要是一些货品信息、税费、运费等详细清单 -
shippingOptions
则是运输相关的选项,有事件监听如果不能送达,则应在 UI 层面给用户提示 -
modifier
主要是针对用户付款方式,修改交易详情,比方说针对某种支付手段给予优惠,展示不同金额等-
additionalDisplayItems
额外需要展示的新增订单项目 -
data
额外信息 -
total
修改后的总价
-
total
这一字段需要填写支付总额,API 不会自动计算,需要计算后填入 total 字段需要满足 PaymentItem
规范
也就是说至少需要一个 label 字符串和一个 PaymentCurrencyAmount
金额,另外还有一个可选项 pending 用来表示是否为最终金额,默认为 false:
PaymentCurrencyAmount 则需要两个属性,一个是 currency 一个是 value,两个都是字符串:
const details = {
total: {
label: '合计总金额 ? ',
amount: { currency: 'CNY', value: '100.00' }
}
}
增加 details 对象,编写代码如上所示
效果如下:
id
id 则代表了交易 ID,可以自定义,字符串格式:
const details = {
id: 'Order-Funny-ID-000-001',
total: {
displayItems
订单详情,每个单个条目最终是否展示取决于浏览器。这是一个数组,数组内每一个对象都是一个 PaymentItem
,因此数组内每一项的规范参照 total:
const details = {
id: 'Order-Funny-ID-000-001',
displayItems: [{
label: '西瓜 ?',
amount: { currency: 'CNY', value: '20.00' }
}, {
label: '草莓 ?',
amount: { currency: 'CNY', value: '90.00' }
}, {
label: 'VIP 会员 ?',
amount: { currency: 'CNY', value: '-10.00' },
pending: true
}],
total: {
label: '合计总金额 ? ',
amount: { currency: 'CNY', value: '100.00' }
}
}
上面代码执行效果长这样:
shippingOptions
根据规范 shippingOptions 应该有三个必选参数,id、label、amount(同样,amount 必须符合 PaymentCurrencyAmount
),selected 默认为 false,是可选参数:
const details = {
id: 'Order-Funny-ID-000-001',
displayItems: [{
}],
total: {
},
shippingOptions: [{
id: '标准快递',
label: '? 免费普通快递 1 天全国范围内',
amount: {
currency: 'CNY',
value: '0.00'
},
selected: true
}, {
id: '东风快递',
label: '? 超快速递 3 小时全球范围内',
amount: {
currency: 'CNY',
value: '100.00'
}
}]
}
const options = {
requestShipping: true // 别忘记这里需要设置为 true
}
let request = new PaymentRequest(
methodData, // 支付方式
details, // 交易信息
options // 其他额外信息
)
按上述规范配置 shippingOptions,并监听配送选项改变或地址改变动态调整收费价格标准
// 监听配送选项改变,动态修改收费标准
request.onshippingoptionchange = function (e) {
console.log('快递选项改变,重新计算价格')
e.updateWith(Promise.resolve(updateDetail(details, request.shippingOption))) // 接收 promise
}
// 监听地址选项改变,动态修改收费标准
request.onshippingaddresschange = function (e) {
console.log('地址选项改变,重新计算价格')
e.updateWith(Promise.resolve(updateDetail(details, request.shippingOption))) // 接收 promise
}
function updateDetail(details, shippingOpts) {
console.log({ details, shippingOpts }) // shippingOpts 代表选择的快递 id
// fetch 后台数据
// 各种判断
// 修改 details 最后 return 出去
// if (shippingOpts) {} else {}
// 这里仅作演示没修改数据
return details
}
modifier
用于修改账单,这里以 visa 卡为例,使用此类型信用卡会在账单中增加一条 additionalDisplayItems,并通过 total 修改账单总额
modifier 需要一个 supportedMethods
为必选参数:
modifiers: [
{
additionalDisplayItems: [{
label: 'visa 手续费',
amount: { currency: 'CNY', value: '10.00' }
}],
supportedMethods: "basic-card",
total: {
label: "Total due",
amount: { currency: "USD", value: "110.00" },
},
data: {
supportedNetworks: ['visa'],
},
},
]
效果如下:
options
主要有六个参数可供配置,分别是 requestPayerName
、requestPayerEmail
、requestPayerPhone
、requestShipping
、requestBillingAddress
、shippingType
,前五项默认为 false,最后一项可设置为 shipping
、delivery
、pickup
,三者根据语境选择合适的 UI 层面对“快递”的描述,这三个单词在中国大陆分别代表送货
、递送
和取货
request 实例的属性和方法
上文提到的 shippingaddresschange
和 shippingoptionchange
就是该实例的两个事件,除此之外还有 paymentmethodchange
和 merchantvalidation
。除事件之外,实例的四个属性分别是 id
、shippingAddress
、shippingOption
、shippingType
可以访问到这个支付请求的相关配置。该实例的三个方法比较重要,用来鉴定是否能够发起支付的 canMakePayment
、调起 UI 支付界面的 show
以及放弃支付的 abort
。
canMakePayment
检测是否支持此种支付方式,在使用之前必须先要判断浏览器是否支持 canMakePayment 本身:
if (request.canMakePayment) {
} else {
+ ;(() => { console.log('浏览器不支持 canMakePayment 特性') })()
}
然后调用方法检测支付:
if (request.canMakePayment) {
+ request.canMakePayment().then(res => {
+ }).catch(console.error)
} else {
; (() => { console.log('浏览器不支持 canMakePayment 特性') })()
}
根据检测结果判断是否进一步调用 show,发起支付:
if (request.canMakePayment) {
request.canMakePayment().then(res => {
+ if (res) {
+ request.show() // true 如果支持
+ } else {
+ console.log('未能发起支付')
+ }
}).catch(console.error)
} else {
; (() => { console.log('浏览器不支持 canMakePayment 特性') })()
}
show
最终获取支付成功的 response 是通过 show 方法返回的,最后确认无误后,调用 response 的 complete 方法,并传入 success
、fail
或 unknow
字段来结束支付:
if (request.canMakePayment) {
request.canMakePayment().then(res => {
if (res) {
+ request.show().then(response => {
+ console.log(response)
+ setTimeout(() => { // 模拟发送支付信息到服务端,并调用 response 的 complete 方法完成支付
+ response.complete()
+ }, 2000)
})
} else {
console.log('未能发起支付')
}
}).catch(console.error)
} else {
; (() => { console.log('浏览器不支持 canMakePayment 特性') })()
}
此外 response 还有 retry 方法,可以在遇到支付 response 出现错误的时候重新发起支付
关于 response 的属性和方法见如下截图:
附上用于测试的信用卡卡号
最后附上用于测试的信用卡卡号,日期随便填,CVC 随便填
Test Credit Card Account Numbers http://www.blogjava.net/sealy...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。