三方接入踩坑集合

| 字数 2166
  1. 1. worldpay俩方
  2. 2. paypal smart button
  3. 3. certona
  4. 4. pinterest
  5. 5. GA
  6. 6. Ping Pong Pay
  1. 1. worldpay俩方
  2. 2. paypal smart button
  3. 3. certona
  4. 4. pinterest
  5. 5. GA
  6. 6. Ping Pong Pay

        在做跨境电商网站的时候避免不了接入三方的支付、统计等代码来进行一系列的数据统计、分析、引流等。这里记录一下自己踩过的坑。

worldpay俩方

        之前不论是 paypal 还是 worldpay 接支付都是跳转到三方页面,因为中间跳转的这一步会导致部分用户弃单,转化率下降。根据我们自己的统计和与海外客户沟通来看得到的结论时尽量不要跳转,所以要把之前的三方改为俩方,即页面中嵌套 iframe 的方式。

  1. 引入资源css/js/helper.html
  2. 创建目标div
  3. 执行setup

具体如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE HTML>
<html>
<head>
<title>My test page</title>
<link rel='stylesheet' href='https://payments.worldpay.com/resources/hpp/integrations/embedded/css/hpp-embedded-integration-library.css'/>
<script src='https://payments.worldpay.com/resources/hpp/integrations/embedded/js/hpp-embedded-integration-library.js'></script>
<head/>

<body>
<div id='custom-html'></div>
<script type='text/javascript'>
var customOptions = {
type: 'lightbox',
iframeIntegrationId: 'libraryObject',
iframeHelperURL: 'https://www.example.com/helper.html',
iframeBaseURL: 'https://www.example.com',
url: 'https://payments.worldpay.com/ngpp/integration/wpg/corporate?OrderKey=YOUR_ORDER_KEY&Ticket=YOUR_TICKET_ID',
target: 'custom-html',
accessibility: true,
debug: false,
language: 'en',
country: 'gb',
preferredPaymentMethod: '',
successURL: 'https://www.example.com/success',
cancelURL: 'https://www.example.com/cancel',
failureURL: 'https://www.example.com/failure',
pendingURL: 'https://www.example.com/pending',
errorURL: 'https://www.example.com/error'
};

//initialise the library and pass options
var libraryObject = new WPCL.Library();
libraryObject.setup(customOptions);
</script>
</body/>
</html/>

需要注意的点如下:

  1. helper.html 必须放在与当前站点同源的环境中(必须符合同源策略),以我们的 java项目 来说,我把 helper.html 放在了 static 目录下,这样避免经过后端的拦截器出现访问不到的情况。结果放在 iframeHelperURL 属性处即可: iframeHelperURL: window.location.origin + '/static/html/helper.html'
  2. 可以在目标 div 中加入 loading 效果,因为 iframe 生成后会直接替换目标 div 中的内容:
1
<div id='custom-html'></div>

=>

1
2
3
4
5
<div id='custom-html'>
<div class="worldpay-loading">
<div class="sp sp-circle"></div>
</div>
</div>

  1. 示例代码中的配置对象 customOptions 中无 inject 属性而且文档中 inject 也是非必填的,但是 hpp-embedded-integration-library.js 这个资源中对这个属性没有做任何空值处理:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    if (self.options.inject === 'immediate') {
    injectIframeToTarget.call(self);
    } else if (self.options.inject === 'onload') {

    if (window.addEventListener) {
    writeMessage.call(self, 'The browser supports addEventListener');
    window.addEventListener('load', self.onloadInject, false);
    } else if (window.attachEvent) {
    writeMessage.call(self, 'The browser supports attachEvent');
    window.attachEvent('onload', self.onloadInject);
    } else {
    writeMessage.call(self, 'ERROR: the browser does not support an onload event-handler');
    }

    } else if (self.options.inject === 'default') {

    window.onload = function (e) {
    injectIframeToTarget.call(self);
    if (e && e.target && e.target != document) {
    self.isFakeLoadEvent = true;
    }
    };

    } else {
    writeMessage.call(self, 'ERROR: accepted parameters are immediate, onload, default');
    }

可以看到如果不配置 inject: immediate|default|onload 的话,这里直接抛出错误,但是这个时候 iframe 并未生成出来所以当前网页的控制台中不会出现任何信息,所以应该将 inject: immediate 加入到配置对象 customOptions 中。

参考资料:

paypal smart button

        做这个的起因是 paypal 来我司吹了一番 smart button(sbp) 对于跨境电商公司是多么的好(自动切换不同语种、避免多次跳转、balblabla)结果真正实施起来出现的 bug 还都是导致 iframe 未生成或者 支付失败的重大 bug ,感觉 sbp 还处于实验阶段。。。

        如果你只需在 pc 上使用 sbp 那么 ie 8+ 没问题,如果要考虑手机、pc、平板等多端环境时,强烈建议暂时不要使用。附上一张考虑多端环境下的 issue 扯皮截图:

spb-bug-issue

接入 pc 的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<script src="//www.paypal.com/sdk/js?client-id=$SITE.paypalClientId&commit=true&locale=$LANG.spbLang&currency=$CURRENCY.code&disable-funding=credit"></script>

<script>
if(!window.paypal) {
console.log('spb error: .js file has some errors when loading');
}else{
paypal.Buttons({
style: {
size: 'responsive',
layout: 'horizontal', // vertical
tagline: true,
label: 'checkout',
shape: 'rect',
},
commit: true,
onInit: function(data, actions){
console.log('onInit, please wait ...');
},
createOrder: function(data, actions){
console.log('createOrder, please wait ...');
// return fetch(ajaxUrl, {
// method: 'get'
// })
// .then(data => data.json())
// .then(function(res) {
// return resolveFunction(res);
// });
return new Promise(function(resolve, reject) {
$.get(ajaxUrl, function(res) {
if(res.code === 1) {
var token = res.data.redirectUrl.split('token=')[1];
result = $.extend(res.data, {token: token})
if(token) {
console.log('send ajax');
resolve(token);
}else {
window.location.href = location;
}
}else{
window.location.href = res.msg || location;
}
})
})
},
// Finalize the transaction
onApprove: function(data, actions){
console.log('onApprove, please wait ...');
var returnUrl = result.returnUrl + "&paymentId=" + data.paymentID + "&token=" + result.token + "&PayerID=" + data.payerID;
actions.redirect(returnUrl);
},
onCancel: function(data, actions){

},
onError: function(err){
console.error('smart payment button has some errors. like: ', err);
return window.location = result.failedUrl + '&err=' + err;
}
}).render(spbEl);
}
</script>

需要注意的点如下:

  1. sbp 在 createOrder 这一步发送请求的时候要么对普通请求进行 promise 化,要么直接使用 fetch。否则会出现 iframe 中一直 loading 的情况

参考资料:

certona

        certona接入应该是我做过最方便快捷的了。

node环境接入如下:

1
2
3
// 当前页面:404.html

<%- include('./analysis/certona.html', {pageType: '404'})%>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 当前页面:certona.html

<script type="text/javascript" src="//edge1.certona.net/YOUR_TAG/scripts/resonance.js"></script>
<script type="text/javascript" id="Certona">
<% if(typeof(pageType) != 'undefined') { %>
<% if(pageType == '404') { %>
var certona = {
"pagetype" : "404ERROR",
"devicetype" : "DESKTOP",
"recommendations" : true
};
<% } %>
<% } %>
</script>

pinterest

  1. 添加主代码与 pagevisti 追踪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<head>
<script type="text/javascript">
!function(e){if(!window.pintrk){window.pintrk=function()
{window.pintrk.queue.push(Array.prototype.slice.call(arguments))};var
n=window.pintrk;n.queue=[],n.version="3.0";var
t=document.createElement("script");t.async=!0,t.src=e;var
r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}
("https://s.pinimg.com/ct/core.js");

pintrk('load','YOUR_TAG_ID');
pintrk('page');
</script>
<noscript>
<img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=YOUR_TAG_ID&noscript=1" />
</noscript>
<script>
pintrk('track', 'pagevisit');
</script>
<noscript>
<img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=YOUR_TAG_ID&event=pagevisit&noscript=1" />
</noscript>
</head>
  1. 支付成功页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<script type="text/javascript">
!function(e){if(!window.pintrk){window.pintrk=function(){window.pintrk.queue.push(
Array.prototype.slice.call(arguments))};var
n=window.pintrk;n.queue=[],n.version="3.0";var
t=document.createElement("script");t.async=!0,t.src=e;var
r=document.getElementsByTagName("script")[0];r.parentNode.insertBefore(t,r)}}("https://s.pinimg.com/ct/core.js");
pintrk('load', 'YOUR_TAG_ID');
pintrk('page');
</script>
<noscript>
<img height="1" width="1" style="display:none;" alt="" src="https://ct.pinterest.com/v3/?tid=YOUR_TAG_ID&noscript=1" />
</noscript>
<script>
pintrk ('track', 'checkout', {});
</script>
<noscript>
<img height="1" width="1" style="display:none;" alt=""
src="https://ct.pinterest.com/v3/?tid=YOUR_TAG_ID&event=checkout&noscript=1" />
</noscript>

需要注意的点如下:

  1. 不论什么三方代码,在支付成功页添加时一定要注意避免刷新后重复上传,一般做法是利用cookie判断。shopify 平台还提供了一个 first_time_accessed 的方法。

GA

        ga的代码文档已经很详细,可以根据业务以及数据的不同维度来自定义上传数据,也没什么深坑,这里就不再阐述了。

Ping Pong Pay

现在大多支付已经从重定向的三方模式,向伪俩方或者俩方的模式发展。毕竟俩方不会跳页面,这样会降低用户的流失率。

在对接这个支付时,采用的是伪俩方的模式,但是 pingpong 的伪俩方并不是直接生成 iframe 而是直接生成 dom,但问题是这个支付生成 dom 的父元素是一个我们自己业务的表单,当切换其他支付单击我们自己的表单提交按钮时 pingpong 的支付也会被触发。与 pingpong 沟通后,对方给了一个动态生成表单的建议。但是鉴于我们接入的支付很多,如果采用动态生成表单需要花时间重构、测试,所以这个意见并没有采纳。不过沟通后当我将 pingpong 的 js 不引入后,上述问题并没用复现。现在的问题就是怎么去除 js 的影响?
首先想到的是删除 script 标签,但是只要 js 加载,即使删除了 dom 代码还是会执行。(具体可参考:Removed JavaScript is still executable)所以需要换一种思路,选择非 pingpong 支付时将该 js 暴露出来的三方对象存起来后直接置 null,当从其他支付切回 pingpong 支付时将存起来的值重新赋回即可。