Stripe - JSON Циркулярная ссылка

Я использую Stripe Checkout.js для создания платежа. Я создаю обработчик, который при успешном выполнении отправляет маркер на сервер:

let handler = StripeCheckout.configure({
                key: 'my_key',
                image: 'image.png',
                locale: 'auto',
                token: token => {

                    console.log(token.id);

                    // ... send token to server
                }
            });

Затем я использую обработчик для создания токена:

handler.open({
    name: 'Test',
    description: 'test',
    billingAddress: false,
    currency: 'eur',
    amount: '1200',
});

Этот обработчик запускает всплывающее окно checkout.js, которое я заполняю и нажимаю Pay. Он заканчивается успешно, то есть кнопка отображается зеленым цветом.

Но между моментом, когда кнопка отображается зеленым цветом, и моментом, когда маркер печатается на консоли (при обратном вызове обработчика), возникает ошибка:

ИСКЛЮЧЕНИЕ: TypeError: преобразование круговой структуры в JSON

Основная часть stacktrace такова:

TypeError: Converting circular structure to JSON
    at Object.stringify (native)
    at Object.stringify (http://localhost:5000/dist/client/bundle.js:46294:29)
    at RPC.sendMessage (https://checkout.stripe.com/checkout.js:1:18068)
    at RPC.sendMessage (https://checkout.stripe.com/checkout.js:1:16180)
    at https://checkout.stripe.com/checkout.js:1:17137
    at RPC.ready (https://checkout.stripe.com/checkout.js:1:17416)
    at RPC.invoke (https://checkout.stripe.com/checkout.js:1:17084)
    at RPC.invoke (https://checkout.stripe.com/checkout.js:1:16180)
    at RPC.processMessage (https://checkout.stripe.com/checkout.js:1:18899)
    at RPC.processMessage (https://checkout.stripe.com/checkout.js:1:16180)

Проверяя код, мы видим, что проблема здесь:

        RPC.prototype.sendMessage = function(method, args) {
            var err, id, message, _ref;
            if (args == null ) {
                args = []
            }
            id = ++this.rpcID;
            if (typeof args[args.length - 1] === "function") {
                this.callbacks[id] = args.pop()
            }
            message = JSON.stringify({
                method: method,
                args: args,
                id: id
            });

Кажется, что Checkout.js создает объект сообщения, который имеет круговую ссылку, затем пытается вызвать JSON.stringify на нем, что вызывает ошибку.

Эта ошибка не является фатальной, и оплата идет, но знаете ли вы, что это может быть и как ее исправить?

Или существует известное обходное решение.

это полная трассировка стека

Обратите внимание, что вызов stringify перед передачей объекта в postMessage может не понадобиться в соответствии с документами MDN.

postMessage использует механизм сериализации, который поддерживает циклические ссылки в соответствии с этим.

Ответы

Ответ 1

Проблема в checkout.js(в строке 780 в файле с уменьшенным размером):

message = JSON.stringify({
    method: method, 
    args: args,
    id: id
});

При работе в Angular2 zone.js завершает обратный вызов с информацией о зоне. Это означает, что параметр args выглядит следующим образом:

[5, ZoneTask]

И, ZoneTask имеет член,.zone, который содержит круговую ссылку: zone -> _zoneDelegate -> zone

JSON.stringify(args[1].zone)
> Uncaught TypeError: Converting circular structure to JSON(…)

Итак, принципиально Stripe checkout.js делает предположение о некруговой, которое больше не действует, когда Zone.js вмешивается. Stripe придется исправлять это.

Тем временем вы можете использовать следующий ужасный взлом. Это так ужасно и так взломанно, что у меня глаза кровоточат, но это лучшее, что я мог придумать, чтобы исправить это, не изменяя код Stripe. По сути, вы глобально замените JSON.stringify версией, которая разбивает любые зоны → _ zoneDelegate- > зоны циклов в объекте, который его просят скрепить:

const _stringify = JSON.stringify;
JSON.stringify = function (value, ...args) {
  if (args.length) {
    return _stringify(value, ...args);
  } else {
    return _stringify(value, function (key, value) {
      if (value && key === 'zone' && value['_zoneDelegate'] 
          && value['_zoneDelegate']['zone'] === value) {
        return undefined;
      }
      return value;
    });
  }
};  

Извините, если у вас теперь кровотечение. Он работает.