Stripe - JSON循环引用

时间:2016-03-28 07:57:19

标签: angular stripe-payments

我正在使用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。它成功结束,意味着按钮显示为绿色。

但是,在按钮显示绿色的那一刻,以及将令牌打印到控制台的那一刻(在处理程序成功回调上),会抛出错误:

  

EXCEPTION: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,这会导致错误。

这个错误是非致命的并且付款通过,但你知道这可能是什么以及如何解决它?

或者是否有已知的解决方法。

这是full stack trace

请注意,根据MDN docs,在将对象传递给stringify 之前调用postMessage可能不需要

postMessage使用支持根据this的循环引用的序列化机制。

1 个答案:

答案 0 :(得分:13)

问题出在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将不得不解决这个问题。

与此同时,您可以使用以下可怕的黑客攻击。它是如此可怕和如此hacky,它让我的眼睛流血,但是 在没有修改Stripe代码的情况下,这是我能想到的最好的解决方法。从本质上讲,您全局将JSON.stringify替换为在要求字符串化的对象中打破任何zone-> _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;
    });
  }
};  

道歉,如果你的眼睛现在流血了。它有效。