iOS Swift基于WKWebView实现3D安全支付的JS POST迁移方案
Swift + WKWebView 实现3D Check支付验证方案
我之前刚把旧的Objective-C+UIWebView的3D支付验证流程迁移到Swift+WKWebView,踩过几个小坑,给你整理一套完整的可行方案,完美适配你描述的支付流程:
核心流程回顾
- 发起支付请求,后端返回包含
PaReq和ACSURL的响应 - 通过WKWebView构造POST请求跳转到ACS验证页面
- 用户完成3D验证后,拦截回调并提取
PaRes参数 - 将
PaRes传入后续支付接口完成流程
具体实现步骤
1. 配置WKWebView与导航代理
首先创建WKWebView并设置导航代理,用来拦截验证完成后的回调URL:
class ThreeDSecureViewController: UIViewController, WKNavigationDelegate { private var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() setupWebView() // 这里替换成你从后端拿到的真实参数 start3DSecureFlow(acsURL: "https://your-payment-gateway-acs.com", paReq: "your-pa-req-token") } private func setupWebView() { let config = WKWebViewConfiguration() // 确保允许JavaScript执行(部分网关依赖JS渲染验证页面) config.preferences.javaScriptEnabled = true webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self webView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(webView) // 约束让WebView铺满整个屏幕 NSLayoutConstraint.activate([ webView.topAnchor.constraint(equalTo: view.topAnchor), webView.leadingAnchor.constraint(equalTo: view.leadingAnchor), webView.trailingAnchor.constraint(equalTo: view.trailingAnchor), webView.bottomAnchor.constraint(equalTo: view.bottomAnchor) ]) } }
2. 构造自动提交的POST表单HTML
WKWebView没有直接的POST请求加载方法,我们可以构造一个自动提交的HTML表单,加载后自动跳转到ACS验证页面:
private func build3DSecureHTML(acsURL: String, paReq: String, termUrl: String) -> String { return """ <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body onload="document.forms['3dForm'].submit()"> <form name="3dForm" method="POST" action="\(acsURL)"> <input type="hidden" name="PaReq" value="\(paReq)"> <input type="hidden" name="TermUrl" value="\(termUrl)"> <!-- 部分支付网关需要额外的MD参数,根据实际需求添加 --> <!-- <input type="hidden" name="MD" value="your-md-identifier"> --> </form> </body> </html> """ } private func start3DSecureFlow(acsURL: String, paReq: String) { // 自定义URL Scheme,用于拦截验证完成后的回调,需要在Info.plist中配置 let termUrl = "yourapp://3dsecure/callback" let htmlContent = build3DSecureHTML(acsURL: acsURL, paReq: paReq, termUrl: termUrl) webView.loadHTMLString(htmlContent, baseURL: nil) }
3. 拦截回调URL提取PaRes
用户完成验证后,支付网关会跳转到我们设置的TermUrl,通过WKNavigationDelegate拦截这个URL并提取PaRes:
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { guard let callbackUrl = navigationAction.request.url else { decisionHandler(.allow) return } // 检查是否是我们自定义的回调Scheme if callbackUrl.scheme == "yourapp" && callbackUrl.host == "3dsecure" && callbackUrl.path == "/callback" { // 解析URL参数,提取PaRes if let urlComponents = URLComponents(url: callbackUrl, resolvingAgainstBaseURL: false), let paResItem = urlComponents.queryItems?.first(where: { $0.name == "PaRes" }), let paResToken = paResItem.value { // 拿到PaRes后,执行后续支付逻辑 processPaymentWithPaRes(paRes: paResToken) } // 取消跳转,因为我们已经拿到需要的参数了 decisionHandler(.cancel) return } // 其他正常页面跳转允许加载 decisionHandler(.allow) } private func processPaymentWithPaRes(paRes: String) { // 这里调用你的后端支付完成接口,传入PaRes print("成功获取PaRes: \(paRes)") // 完成后可以关闭当前验证页面,回到支付流程 dismiss(animated: true) }
4. 配置Info.plist的URL Scheme
在Info.plist中添加自定义URL Scheme,确保APP能拦截到回调链接:
<key>CFBundleURLTypes</key> <array> <dict> <key>CFBundleURLSchemes</key> <array> <string>yourapp</string> <!-- 替换成你的APP自定义Scheme --> </array> </dict> </array>
额外处理:错误与异常情况
别忘了添加错误处理,比如页面加载失败时提示用户:
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) { showErrorAlert(message: "验证页面加载失败,请重试") } func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) { showErrorAlert(message: "验证请求失败,请检查网络或重试") } private func showErrorAlert(message: String) { let alert = UIAlertController(title: "提示", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) }
关键注意事项
- TermUrl设置:部分支付网关要求TermUrl为HTTPS地址,这种情况下需要后端配合:网关跳转到后端的HTTPS回调地址,后端再通过APP的URL Scheme将PaRes参数传递回来
- 参数完整性:有些网关会要求额外的
MD参数(支付会话标识),需要和后端确认后添加到表单中 - WKWebView权限:确保开启JavaScript支持,部分3D验证页面依赖JS渲染交互组件
内容的提问来源于stack exchange,提问作者RavikanthM
相关产品推荐
相关产品推荐

