前端ApplePay支付-H5全流程實戰指南

提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔


前言

近期公司開展關于蘋果支付的相關業務,與之前不同的是,以前后臺直接獲取第三方Wallet封裝好的接口獲取支付地址,H5頁面直接跳轉使用ApplePay支付就行了,相當于第三方直接和銀行達成合作;如今,需要我們和銀行合作,自己去拉取ApplePay支付。沒錯,又是一個學習和摸索的一個階段,哈哈哈哈,如果有不對的地方,歡迎大家指正!!

一、前期工作

  1. 注冊蘋果開發者賬號
  2. 創建一個AppId
  3. 完成商戶驗證,配置商戶號:銀行需與 Apple 交換加密證書,用于驗證支付請求的合法性和安全性,同時配置商戶號Merchant Identity并綁定支付的域名
  4. 生產環境必須使用HTTPS,沙盒可以使用HTTP,但商戶驗證仍需HTTPS

PS:銀行提供支付處理證書,使用該證書提交到Apple開發者后臺用于獲取商戶身份證書。
具體包括:

  • 商戶身份證書(Merchant Identity Certificate):由銀行協助商戶在 Apple 開發者后臺申請,用于前端喚起 Apple Pay 時的身份驗證。
  • 支付處理證書(Payment Processing Certificate):銀行需支持解密 Apple Pay 生成的支付令牌(Token),通常由銀行提供證書或密鑰給商戶的支付服務商。

二、前端后端支付流程

1.初始校驗
作用:驗證是否存在ApplePay內核,存在則顯示ApplePay支付方式

?內核主要是喚起 Apple Pay 界面、收集用戶支付信息(如銀行卡、金額)、生成加密的 “支付令牌(Payment Token)” 并傳遞給后端。

// 檢驗ApplePay環境 - 針對存在applePay內核時,才顯示ApplePay支付方式
async checkApplePaySupport() {if (!window.ApplePaySession) {//瀏覽器不支持 Apple Paythis.isApplePaySupported = falsereturn}try {// 檢測當前設備是否支持 Apple Pay 功能const canMakePayments = await ApplePaySession.canMakePayments(); // 用于檢查設備是否支持 Apple Pay 并且 用戶已添加至少一張有效支付卡。const canMakePaymentsWithActiveCard = await ApplePaySession.canMakePaymentsWithActiveCard(this.merchantIdentifier); if (canMakePayments && canMakePaymentsWithActiveCard) {this.isApplePaySupported = true} else if (!canMakePayments) { // 設備不支持 Apple Paythis.isApplePaySupported = falseconsole.log('設備不支持 Apple Pay')} else { // 未添加支付有效卡this.isApplePaySupported = trueconsole.log('未添加支付有效卡')}} catch (error) {// 檢查失敗: ${error.message}`this.isApplePaySupported = falseconsole.log(error.message)}// console.log('是否支持Apple',this.isApplePaySupported)// // 測試支持的支付網絡 - 低版本不支持-所以干脆去掉了// ApplePaySession.getApplePayCapability({//   merchantIdentifier: this.merchantIdentifier,//   supportedNetworks: ['visa', 'masterCard', 'chinaUnionPay', 'amex', 'jcb']// })// .then(capabilities => console.log('支持的網絡:', capabilities.supportedNetworks))// .catch(error => console.error('檢測失敗:', error));
},
?2.?商戶驗證流程
  1. 前端創建會話?ApplePaySession,設置會話最長等待時長
  2. 前端觸發onvalidatemerchant商戶驗證事件
  3. 前端將獲取到的?validationURL?通過后端提供的商戶驗證接口傳遞給后端
  4. 后端使用validationURL與商戶證書向 Apple 服務器請求商戶信息?merchantSession
  5. 后端返回?merchantSession?給前端,確保?merchantIdentifier?與前端一致(返回的MID可能是hash字符串)
  6. 前端調用?session.completeMerchantValidation?完成商戶驗證
3.?支付驗證流程
  1. 用戶授權支付后,觸發?onpaymentauthorized?事件
  2. 前端將支付令牌?paymentToken?發送到后端
  3. 后端將支付令牌轉發給支付網關(如 Stripe、銀聯)
  4. 后端返回支付結果給前端
  5. 前端調用?session.completePayment?通知 Apple Pay 支付狀態

?用戶授權支付動作:指的是輸入了支付密碼這個動作,當初因為測試機沒有卡,一直無法觸發支付驗證事件,找了半天原因。

// ApplePay支付
applePayClicked() {this.session = null// 預支付信息const paymentRequest = {countryCode: 'HK',// 交易的國家currencyCode: 'HKD',// 貨幣supportedNetworks: ['visa', 'masterCard', 'chinaUnionPay', 'amex', 'jcb'],// supportedNetworks 列出支持的卡 chinaUnionPay 銀聯merchantCapabilities: ['supports3DS'],// 支持的支付特性total: { label: 'XXX電子支付', // 支付的標簽和金額amount: 100.00,type: 'final' },}// 1.創建ApplePay支付會話this.session = new window.ApplePaySession(3, paymentRequest);// 設置會話最長等待時間this.session.timeoutInterval = 120; // 單位:秒// 2.觸發商戶驗證事件 - 獲取validationURL,傳遞給后臺this.session.onvalidatemerchant = (event) => {this.validateMerchant(event.validationURL)};// 3.支付授權事件 - 用戶授權支付后,觸發?onpaymentauthorized?事件this.session.onpaymentauthorized = async(event) => {console.log('=== 支付授權 ===');this.info = event // 3.1 獲取paymentTokenlet paymentToken  = event.payment.token.paymentData; this.paymentToken = JSON.stringify(paymentToken) || ''// 3.2 前端將支付令牌paymentToken+訂單信息發送到后端 let initPayResult = await this.goPay();if(initPayResult =='fail'){ // this.goPay() 提交訂單信息,接口返回錯誤時,關閉當前會話this.session.completePayment(window.ApplePaySession.STATUS_FAILURE);return}// 3.3 輪詢訂單查詢接口try{ this.applyPayRes = searchApi({orderId:this.id});let res = await this.applyPayResif(res.status===0){ // 3.4 查詢到訂單結果 - 需要completePayment 通知 Apple Pay 支付狀態await this.session.completePayment(window.ApplePaySession.STATUS_SUCCESS); // 必須調用!!!// 跳轉成功界面uni.navigateTo({url:'XXXXXURL',})}else{await this.session.completePayment(window.ApplePaySession.STATUS_FAILURE);this.openPopup('該訂單查詢結果失敗')}}catch(error){console.log('支付報錯',error)this.applyPayRes = null;this.session.completePayment(window.ApplePaySession.STATUS_FAILURE);}finally{ // 輪詢完成或失敗時才重置實例this.applePayRes = null}};// 4.錯誤事件this.session.onerror = (error) => {console.error('Apple Pay 錯誤:', error);this.openPopup('支付錯誤: ${error.message}')};// 5.取消事件this.session.oncancel = () => {console.log('用戶取消支付');this.cancelPolling() // 取消輪詢 this.session = null;};// 啟動支付流程this.session.begin();  
},
// 2.1 ApplePay商戶驗證(調用后端 API)- 實現商戶驗證邏輯
validateMerchant(validationURL) {return new Promise((resolve, reject) => {uni.request({url: '/XXXX/validate',method: 'POST',data: { validationURL },success: (res) => {if (res.data.success) { // res.data.success =truelet merchantSession = res.data.dataif (this.validateMerchantSession(merchantSession)) { // 校驗接口返回字段// 2.3 完成商戶驗證this.session.completeMerchantValidation(merchantSession);resolve(merchantSession);} else {reject(new Error('商戶會話數據無效'));}} else {reject(new Error(res.data.message));}},fail: (err) => {console.error('商戶驗證請求失敗:', err);reject(err);}});});
},// 2.2 驗證商戶會話接口返回數據
validateMerchantSession(sessionData) {const requiredFields = ['signature', 'merchantIdentifier', 'domainName', 'expiresAt'];for (const field of requiredFields) {if (!sessionData[field]) {console.error(`缺少必需字段: ${field}`);return false;}}// 驗證域名一致性if (sessionData.domainName !== window.location.hostname) {console.error(`域名不匹配: ${sessionData.domainName} vs ${window.location.hostname}`);return false;}// 驗證有效期if (sessionData.expiresAt < Date.now()) {console.error('商戶會話已過期');return false;}return true;
}

三、調試與部署注意事項

1.證書配置?
  • 確保后端持有有效的 Apple Pay 商戶證書和私鑰
  • 證書需與商戶 ID 和域名匹配
2.HTTPS要求
  • 生產環境必須使用 HTTPS
  • 沙盒環境可以使用 HTTP,但商戶驗證仍需 HTTPS
3.地區與貨幣
  • 針對香港或內地用戶,對應的國家地區countryCode與貨幣currencyCode是不一樣的,香港countryCode:'HK',currencyCode:'HKD';而澳門是'MO' 與'MOP'
  • 確保支付網關支持香港或內地地區的貨幣和卡組織
  • PS:一定要注意卡卡卡!!!我們做的香港業務,內地支付卡是無效的!所以需要包含對應地區的支付卡,哪怕內地卡是可以輸入密碼,但仍然無法獲取后臺所需要的paymentToken參數,甚至就跟陷入無限循環一樣,不扣錢但也無法獲取參數。
4.商戶ID一致性
  • 確保?merchantIdentifier?與證書中的商戶 ID 一致

商戶Id如果不正確會導致拉取ApplePay會話后,可進行商戶驗證,但無法觸發支付驗證并且界面立刻關閉。后端在商戶驗證的接口中返回merchantIdentifier?是一串hash數字,經過加密的,無需前端處理,直接將獲取得到的數據進行商戶校驗即可。

5.使用completePayment 告知ApplePay支付結果

支付查詢到結果后使用completePayment告知ApplePay會話結果;如果不調用會導致會話持續處于 "處理中" 狀態。

我就是沒調用告知結果,付完錢一直擱那溜溜轉了很久,最終界面顯示取消支付,立刻關閉。

四、報錯記錄:

1. payment Services Exception merchantId=XXX not registered for domain=XXX 報錯
  1. 商戶 ID 未注冊:商戶 ID(XXX)可能未在支付服務提供商處完成注冊或激活。
  2. 域名未配置:支付服務提供商可能未將?https://xxx.com?添加到該商戶 ID 的允許域名列表中。
  3. 配置延遲:新注冊的商戶 ID 或域名配置可能需要時間生效(例如,需等待幾分鐘至幾小時)。
  4. 域名不匹配:檢查 URL 是否包含端口號、子域名等額外信息。
  5. 測試環境與生產環境混淆:確認使用的商戶 ID 和 API 密鑰對應正確的環境(測試 / 生產)。
2.?ApplePay報錯:must create a new ApplePaySession from a user gesture handler;
  1. 嚴格的用戶手勢要求:Apple Pay 會話必須直接在用戶點擊事件的處理函數中創建,不能通過 Promise、setTimeout、await 或其他異步方式延遲創建。(我就是在點擊時先進行了訂單查詢的動作,再去創建ApplePay會話,存在異步操作,導致ApplePay會話都不創建了!!!)

  2. 避免預創建會話:不要在頁面加載時或其他非交互時機創建?ApplePaySession?實例。

  3. 驗證用戶交互:確保你的按鈕或其他交互元素確實被用戶點擊后才觸發會話創建。

3.商戶驗證后會話立即關閉,提示未完成付款?
? ?1.?支付請求參數配置錯誤
  • countryCode?與?currencyCode?不匹配(如使用?HK?國家代碼但貨幣為?CNY
  • supportedNetworks?中無用戶已添加的有效卡類型
  • total?金額格式或精度不符合要求
? ?2.?商戶驗證流程問題
  • 商戶證書與實際域名不匹配
  • merchantSession?中的簽名或時間戳無效
  • 后端驗證接口響應超時
? ?3.?設備或用戶環境問題
  • 設備未添加有效支付卡
  • 支付卡已過期或被凍結
  • iOS 設置中的 Apple Pay 權限異常

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90913.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90913.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90913.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Flink窗口:解鎖流計算的秘密武器

Flink 窗口初識在大數據的世界里&#xff0c;數據源源不斷地產生&#xff0c;形成了所謂的 “無限數據流”。想象一下&#xff0c;網絡流量監控中&#xff0c;每一秒都有海量的數據包在網絡中穿梭&#xff0c;這些數據構成了一個無始無終的流。對于這樣的無限數據流&#xff0c…

Java排序算法之<希爾排序>

目錄 1、希爾排序介紹 1.1、定義 1.2、核心思想 2、希爾排序的流程 第 1 輪&#xff1a;gap 4 第 2 輪&#xff1a;gap 2 第 3 輪&#xff1a;gap 1 3、希爾排序的實現 4、時間復雜度分析 5、希爾排序的優缺點 6、適用場景 前言 希爾排序&#xff08;Shell Sort&…

c++加載qml文件

這里展示了c加載qml文件的三種方式以及qml文件中根節點的訪問準備在創建工程的初期&#xff0c;遇到了一個問題&#xff0c;cmake文件以前都是系統自動生成的&#xff0c;不需要我做過多的操作修改&#xff0c;但是&#xff0c;加載qml的程序主函數是需要用到QGuiApplication&a…

007TG洞察:GPT-5前瞻與AI時代競爭力構建:技術挑戰與落地路徑

最近&#xff0c;GPT-5 即將發布的消息刷爆了科技圈&#xff0c;更讓人期待的是&#xff0c;GPT-6 已經悄悄啟動訓練了&#xff0c;OpenAI 的奧特曼表示對未來1-2年的模型充滿信心&#xff0c;預測AI將進化為能夠發現新知識的“AI科學家”。面對日益強大的通用AI&#xff0c;企…

Windows下編譯OpenVDB

本文記錄在Windows下編譯OpenVDB的流程。 零、環境 操作系統Windows 11VS Code1.92.1Git2.34.1MSYS2msys2-x86_64-20240507Visual StudioVisual Studio Community 2022CMake3.22.1 一、編譯 1.1 下載 git clone https://github.com/AcademySoftwareFoundation/openvdb.git …

react 內置hooks 詳細使用場景,使用案例

useState場景&#xff1a;組件中管理局部狀態&#xff0c;如表單值、開關、計數器等。const [count, setCount] useState(0); return <button onClick{() > setCount(count 1)}>Click {count}</button>;useEffect 場景&#xff1a;組件掛載時執行副作用&#…

從0到1學Pandas(九):Pandas 高級數據結構與操作

目錄一、探秘多級索引1.1 創建多級索引1.2 多級索引操作1.3 索引轉換二、探索 Panel 與 xarray2.1 Panel 數據結構2.2 xarray 庫2.3 高維數據操作三、時間序列高級應用3.1 時區處理3.2 時間序列重采樣與頻率轉換3.3 時間序列分解與預測四、數據透視與重塑高級技巧4.1 復雜透視表…

C# 圖像轉換實戰:Bitmap 轉 BitmapSource 的 2 種方法

C# 圖像轉換實戰:Bitmap 轉 BitmapSource 的 2 種方法 引言 兩種轉換方法的完整實現 1. 基于GDI句柄的直接轉換 (ToBitmapSourceFast) 2. 基于內存流的編碼轉換 (ToBitmapSourceSafe) 方法對比與選型指南 避坑指南 GDI句柄泄漏問題 圖像顯示不完整 多線程訪問圖像引發異常 不同…

Spring Boot 整合 Spring MVC:自動配置與擴展實踐

Spring MVC 作為 Java Web 開發的核心框架&#xff0c;在傳統 SSM 項目中需要大量 XML 配置&#xff08;如 DispatcherServlet、視圖解析器等&#xff09;。而 Spring Boot 通過 "自動配置" 特性&#xff0c;簡化了 Spring MVC 的整合過程&#xff0c;同時保留了靈活…

print(“\033[31m紅\033[32m綠\033[34m藍\033[0m默認色“)

可以讓python的終端字體有著不一樣的顏色。代碼&#xff1a;print("\033[31m紅\033[32m綠\033[34m藍\033[0m默認色")效果&#xff1a;

LNMP-zblog分布式部署

一、準備3臺主機&#xff08;rocky8&#xff09;下載相應服務[rootnginx ~]# yum install -y nginx nfs-utils[rootphp ~]# yum install -y nfs-utils php-mysqlnd php php-fpm[rootmysql ~]# yum install -y mysql-server二、掛載php端[rootphp ~]# vim /etc/exports [rootphp…

常見代碼八股

1. 利用梯度下降法&#xff0c;計算二次函數yx^2x4的最小值 def target_function(x):return x ** 2 x 4def gradient(x):return 2*x 1x_init 10 x x_init steps 100 lr 0.1 for i in range(100):x x - lr*gradient(x)print(f"最小值 f(x) {target_function(x):.4f…

【深入底層】C++開發簡歷4+4技能描述6

簡歷書寫 熟悉C的封裝、繼承、多態&#xff0c;STL常用容器&#xff0c;熟悉C11的Lambda表達式、智能指針等&#xff0c;熟悉C20協程語法&#xff0c;具有良好的編碼習慣與文檔能力。 回答思路 這里是基本上就是要全會&#xff0c;考察的問題也很固定&#xff0c;stl這塊可以定…

forest遠程調用注意事項

1、如果在項目中&#xff0c;同時依賴了其中多個框架&#xff0c;那么按 Fastjson2 > Fastjson > Jackson > Gson 這樣的優先級來判斷&#xff0c;Forest 會以優先級最高的框架作為 JSON 轉換器。2、Forest 支持哪幾種 JSON 框架&#xff1f;A: 支持 Jackson、Gson、F…

網絡資源模板--基于Android Studio 實現的新聞App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 登錄頁 首頁 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載也可…

通過Location API精準獲取位置信息并優化定位精度!

&#x1f44b; 你好&#xff0c;歡迎來到我的博客&#xff01;我是【菜鳥不學編程】 ?? 我是一個正在奮斗中的職場碼農&#xff0c;步入職場多年&#xff0c;正在從“小碼農”慢慢成長為有深度、有思考的技術人。在這條不斷進階的路上&#xff0c;我決定記錄下自己的學習與成…

構建可擴展的狀態系統:基于 ArkTS 的模塊化狀態管理設計與實現

摘要 在 HarmonyOS 的日常開發中&#xff0c;很多人都會遇到一個問題&#xff1a;多個頁面之間的數據狀態如何共享&#xff1f;尤其是在組件結構越來越復雜的場景下&#xff0c;如果還用傳統方式來傳值&#xff0c;不僅代碼混亂&#xff0c;維護也很吃力。 為了解決這個問題&am…

重生之我在暑假學習微服務第二天《MybatisPlus-下篇》

本系列參考黑馬程序員微服務課程&#xff0c;有興趣的可以去查看相關視頻&#xff0c;本系列內容采用漸進式方式講解微服務核心概念與實踐方法&#xff0c;每日更新確保知識點的連貫性。通過系統化學習路徑幫助開發者掌握分布式系統構建的關鍵技術。讀者可通過平臺訂閱功能獲取…

系統整理Python的條件語句和常用方法

Python 的條件語句&#xff08;if 語句&#xff09;是控制程序流程的基礎之一&#xff0c;結構清晰、語法簡潔&#xff0c;非常適合初學者掌握。一、基本語法結構if 條件:執行代碼塊1 elif 條件2:執行代碼塊2 else:執行代碼塊3示例&#xff1a;score 85if score > 90:print…

記錄個IAR程序下載后硬件復位不運行,必須斷電復位才運行的問題

【問題測試】有個F407的跑馬燈的例子&#xff0c;是MDK和IAR兩個版本&#xff0c;MDK版本的例子下載并復位后可以正常看到LED閃爍&#xff0c;而IAR的例子下進去后&#xff0c;不會閃爍。使用TOOL的上位機內核寄存器監測工具測試發現&#xff0c;硬件復位后竟然還在調試狀態&am…