Realex支付API场景下如何不通过模拟点击触发点击事件
问题本质
浏览器弹窗拦截的核心规则是:只有用户主动交互(点击、键盘输入等)事件的同步执行上下文中触发的弹窗才会被放行,异步回调(比如AJAX回调、Promise.then回调)已经脱离了用户交互的上下文,即便你在回调里模拟点击,也会被判定为非用户主动触发的垃圾弹窗。
以下方案均满足不改造#rhpp元素、不需要用户额外手动点击的要求:
方案1:提前预拉取订单参数,把弹窗触发放回用户点击的同步上下文
该方案体验最优,无额外感知。你可以在用户进入订单确认页、或者填完所有订单必填项的时候,就提前发起processOrder的请求,把返回的支付参数先缓存下来,等用户点击提交按钮的同步逻辑里直接初始化Realex组件、触发模拟点击:
// 提前缓存支付参数 let payParams = null; // 进入订单确认页时就预请求订单参数 $(function(){ $.ajax({ method: 'POST', url: 'processOrder.php', data: $('form').serialize(), }).done(function(response){ payParams = response; }).fail(function(){ console.log('预拉取订单参数失败'); }) }) // 用户点击提交按钮的同步逻辑 $('#submitOrderBtn').click(function(){ if(!payParams) { // 极端情况预拉取没完成,可以加个loading等参数返回再执行,或者降级成同步请求 alert('订单信息加载中,请稍后再试'); return false; } RealexHpp.setHppUrl('https://pay.sandbox.realexpayments.com/pay'); RealexHpp.lightbox.init('rhpp', payParams.return, JSON.parse(payParams.hpp)); $('#rhpp').click(); })
如果订单参数和用户实时选择的配置(比如优惠券、配送方式)关联,你可以监听这些配置的变更事件,每次变更后重新发起请求更新缓存的参数即可。
方案2:把订单请求改成同步阻塞请求
如果你不想调整预拉取逻辑,可以直接把现有AJAX改成同步模式,让整个请求阻塞在用户点击的同步上下文里,后续的模拟点击还是属于用户交互触发的链路,不会被拦截:
$('#submitOrderBtn').click(function(){ new Promise((resolve,reject) => { $.ajax({ method: 'POST', url: 'processOrder.php', data: $('form').serialize(), async: false, // 新增这行,开启同步请求 }).done(function(response){ resolve(response); }).fail(function(){ reject('Response failed'); }) }).then((data) => { RealexHpp.setHppUrl('https://pay.sandbox.realexpayments.com/pay'); RealexHpp.lightbox.init('rhpp', data.return, JSON.parse(data.hpp)); $('#rhpp').click(); }).catch((error) => { console.log(error); }); })
注意该方案的缺点是请求过程中页面会处于不可操作的卡顿状态,适合请求耗时较短的场景。
方案3:用户点击时先预开空白弹窗,异步请求完成后回填支付内容
如果你既不想用同步请求,也不能提前预拉取参数,可以在用户点击提交的同步逻辑里先打开一个空白的弹窗占位,等AJAX拿到支付参数后,再把Realex的支付内容填充到这个预开的弹窗里即可,因为弹窗本身是用户主动点击触发的,不会被拦截。该方案需要额外处理请求失败的情况,失败后要关闭预开的弹窗,给用户提示错误。
内容的提问来源于stack exchange,提问作者Chaosxmk
相关产品推荐
相关产品推荐

