Размещение кнопок PayPal внутри Vue.js компонент

#javascript #vue.js #paypal #vue-component

#javascript #vue.js #paypal #vue-компонент

Вопрос:

Я пытаюсь разместить кнопки заказа PayPal внутри моего Vue.js компонент.

Я следую официальной документации, в которой в основном говорится, что нужно сделать 3 вещи:

  1. Импортируйте скрипт PayPal SDK
  2. Определите <div> элемент, в котором будут отображаться кнопки
  3. Добавьте некоторый javascript для настройки обратных вызовов и отображения кнопок с использованием переменной paypal

Вот как это выглядит, когда я делаю это в простом HTML-файле:

 <!-- 1 -->

<script src="https://www.paypal.com/sdk/js?amp;client-id=xxx"></script>

<!-- 2 -->

<div id="paypal-button-container"></div>

<!-- 3 -->

<script>
  paypal.Buttons({
    createOrder: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', {
        method: 'POST'
      }).then(function(res) {
        return res.json();
      }).then(function(data) {
        return data.id;
      });
    },
    onApprove: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/'   data.orderID, {
        method: 'POST'
      }).then(function(res) {
        if (!res.ok) {
          alert('Something went wrong');
        }
      });
    }
  }).render('#paypal-button-container');
</script>
  

Приведенный выше код работает. Моя проблема в том, как это сделать в Vue.js компонент.

Для шага 1 я использовал такой mounted() хук:

 mounted() {
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?amp;client-id=xxx')
    document.head.appendChild(payPalSdk)
}
  

Шаг 2 был простым, я просто добавил div элемент в шаблон.

Но куда я должен поместить код javascript для выполнения шага 3?

Я попытался поместить его во внешний js-файл и загрузить его следующим mounted() образом:

 mounted() {
    let payPalSdk = document.createElement('script')
    payPalSdk.setAttribute('src', 'https://www.paypal.com/sdk/js?amp;client-id=xxx')
    document.head.appendChild(payPalSdk)

    let payPalScript = document.createElement('script')
    payPalScript.setAttribute('src', '/js/paypal.js')
    document.head.appendChild(payPalScript)
}
  

paypal.js:

   paypal.Buttons({
    createOrder: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/create-order', {
        method: 'POST'
      }).then(function(res) {
        return res.json();
      }).then(function(data) {
        return data.id;
      });
    },
    onApprove: function (data, actions) {
      return fetch('http://localhost:8081/api/v1/pay-pal/capture-order/'   data.orderID, {
        method: 'POST'
      }).then(function(res) {
        if (!res.ok) {
          alert('Something went wrong');
        }
      });
    }
  }).render('#paypal-button-container');
  

Кнопки действительно отображаются, но консоль показывает следующую ошибку:

 buttons?style.layout…reamp;commit=true:1182 unhandled_error 
{err: "Error: Invalid json: .↵    at XMLHttpRequest.<anon…rrency=USDamp;intent=captureamp;commit=true:1182:22901)", timestamp: "1605367583366", referer: "www.sandbox.paypal.com", sdkCorrelationID: "7d650f42fd450", sessionID: "09b33213cd_mtu6mjy6mja", …}
buttonCorrelationID: "72135879fd67d"
buttonSessionID: "473d7ab57f_mtu6mjy6mja"
env: "sandbox"
err: "Error: Invalid json: .↵    at XMLHttpRequest.<anonymous> (https://www.sandbox.paypal.com/smart/buttons?style.layout=verticalamp;style.color=goldamp;style.shape=rectamp;style.tagline=falseamp;components.0=buttonsamp;locale.country=USamp;locale.lang=enamp;sdkMeta=eyJ1cmwiOiJodHRwczovL3d3dy5wYXlwYWwuY29tL3Nkay9qcz8mY2xpZW50LWlkPUFUX1hyMUl3ekZpM2ItRmhFd0RMQ0VndEM2Y2F4MHgwaWR1VF9yeEprQUhycFRlUXpkbHZRRDhKWFUxZmlNQ01vclN3T1hSWWU1eVVPaENBIiwiYXR0cnMiOnsiZGF0YS11aWQiOiJlOGQyMGY4MzBlX210dTZtank2bWphIn19amp;clientID=xxxamp;sessionID=09b33213cd_mtu6mjy6mjaamp;buttonSessionID=473d7ab57f_mtu6mjy6mjaamp;enableBNPL=trueamp;env=sandboxamp;fundingEligibility=eyJwYXlwYWwiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sInBheWxhdGVyIjp7ImVsaWdpYmxlIjpmYWxzZSwicHJvZHVjdHMiOnsiZmxleCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwYXlJbjQiOnsiZWxpZ2libGUiOmZhbHNlfX19LCJjYXJkIjp7ImVsaWdpYmxlIjp0cnVlLCJicmFuZGVkIjp0cnVlLCJpbnN0YWxsbWVudHMiOmZhbHNlLCJ2ZW5kb3JzIjp7InZpc2EiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sIm1hc3RlcmNhcmQiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImFtZXgiOnsiZWxpZ2libGUiOnRydWUsInZhdWx0YWJsZSI6dHJ1ZX0sImRpc2NvdmVyIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiaGlwZXIiOnsiZWxpZ2libGUiOmZhbHNlLCJ2YXVsdGFibGUiOmZhbHNlfSwiZWxvIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfSwiamNiIjp7ImVsaWdpYmxlIjpmYWxzZSwidmF1bHRhYmxlIjp0cnVlfX19LCJ2ZW5tbyI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJpdGF1Ijp7ImVsaWdpYmxlIjpmYWxzZX0sImNyZWRpdCI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJzZXBhIjp7ImVsaWdpYmxlIjpmYWxzZX0sImlkZWFsIjp7ImVsaWdpYmxlIjpmYWxzZX0sImJhbmNvbnRhY3QiOnsiZWxpZ2libGUiOmZhbHNlfSwiZ2lyb3BheSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJlcHMiOnsiZWxpZ2libGUiOmZhbHNlfSwic29mb3J0Ijp7ImVsaWdpYmxlIjpmYWxzZX0sIm15YmFuayI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJwMjQiOnsiZWxpZ2libGUiOmZhbHNlfSwiemltcGxlciI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJ3ZWNoYXRwYXkiOnsiZWxpZ2libGUiOmZhbHNlfSwicGF5dSI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJibGlrIjp7ImVsaWdpYmxlIjpmYWxzZX0sInRydXN0bHkiOnsiZWxpZ2libGUiOmZhbHNlfSwib3h4byI6eyJlbGlnaWJsZSI6ZmFsc2V9LCJtYXhpbWEiOnsiZWxpZ2libGUiOmZhbHNlfSwiYm9sZXRvIjp7ImVsaWdpYmxlIjpmYWxzZX0sIm1lcmNhZG9wYWdvIjp7ImVsaWdpYmxlIjpmYWxzZX19amp;platform=desktopamp;flow=purchaseamp;currency=USDamp;intent=captureamp;commit=true:1182:22901)"
referer: "www.sandbox.paypal.com"
sdkCorrelationID: "7d650f42fd450"
sessionID: "09b33213cd_mtu6mjy6mja"
timestamp: "1605367583366"
__proto__: Object
y   @   buttons?style.layout…reamp;commit=true:1182
S   @   buttons?style.layout…reamp;commit=true:1182
error   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
setTimeout (async)      
n.reject    @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.reject    @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.reject    @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.reject    @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
load (async)        
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
e   @   buttons?style.layout…reamp;commit=true:1182
ke  @   buttons?style.layout…reamp;commit=true:1182
Oe  @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
e.try   @   buttons?style.layout…reamp;commit=true:1182
w   @   buttons?style.layout…reamp;commit=true:1182
e.try   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
setTimeout (async)      
w::promiseDebounced @   buttons?style.layout…reamp;commit=true:1182
G.then.intent   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
n.dispatch  @   buttons?style.layout…reamp;commit=true:1182
n.resolve   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
setInterval (async)     
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
e   @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1182
anonymous::memoized @   buttons?style.layout…reamp;commit=true:1182
G.style @   buttons?style.layout…reamp;commit=true:1182
ht  @   buttons?style.layout…reamp;commit=true:1182
(anonymous) @   buttons?style.layout…reamp;commit=true:1183
  

Я также попытался поместить код в mounted() хук, но это не сработало, потому что переменная paypal там не определена.

Комментарии:

1. @tao этот URL-адрес фактически возвращает HTML, а не JSON. И это не проблема, потому что он возвращает тот же HTML, когда я пробовал его в рабочем примере.

Ответ №1:

Попробуйте это из mounted(), посмотрите, повлияет ли использование обратного вызова после загрузки PayPal JS или клиентского CreateOrder / onApprove

 function loadAsync(url, callback) {
  var s = document.createElement('script');
  s.setAttribute('src', url); s.onload = callback;
  document.head.insertBefore(s, document.head.firstElementChild);
}

loadAsync('https://www.paypal.com/sdk/js?client-id=sbamp;currency=USD', function() {
  paypal.Buttons({

    // Set up the transaction
    createOrder: function(data, actions) {
        return actions.order.create({
            purchase_units: [{
                amount: {
                    value: '0.01'
                }
            }]
        });
    },

    // Finalize the transaction
    onApprove: function(data, actions) {
        return actions.order.capture().then(function(details) {
            // Show a success message to the buyer
            alert('Transaction completed by '   details.payer.name.given_name);
        });
    }

  }).render('#paypal-button-container');
});
  

Что касается фактического кода утверждения на стороне клиента для продолжения и сопряжения с серверной частью вашего сервера, я рекомендую обработку ошибок https://developer.paypal.com/demo/checkout/#/pattern/server

Комментарии:

1. Спасибо, я попробовал это так, но я получаю точно такую же ошибку.

2. Что-то в вашей среде vue мешает или предотвращает запросы XHR. Проверьте вкладку Сеть и заголовки перекрестных сайтов.

3. Все вызовы paypal.com на вкладке сеть верните значение 200. Что вы подразумеваете под «проверкой заголовков разных сайтов»?

4. Если их 200, как насчет того, что тело ответа не является JSON?

5. Я не вижу никаких запросов, которые возвращают JSON. Даже в рабочем примере.