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 見這篇文章:www.cardinalcommerce.com/startups/on…
根據規範,我們編寫以下程式碼 ?
const methodData = [{
supportedMethods: 'basic-card',
data: {
supportedNetworks: ['visa', 'mastercard', 'amex', 'jcb', 'diners', 'discover', 'mir', 'unionpay']
}
}]
複製程式碼
在呼叫的時候長這樣:
另外,Apple Pay 也支援該特性,詳細見文件:webkit.org/blog/8182/i…
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 www.blogjava.net/sealyu/arch…
最後程式碼在此:codepen.io/oliyg/pen/P…