PAYATHON 2026

NAB 3DS 请求未发送完整 JSON data

支付阿杰

结论

accountData 和 billingAddress 不应与 cardholderInfo 并列,而应放在 cardholderInfo 内部。

NAB 的 securepay-threeds.js 会按预期结构重新组装请求,只读取 callback 返回值中的 cardholderInfo。因此,与它并列的 accountData 和 billingAddress 会被丢弃。删除 cardholderInfo 后,请求变为 null,也与这一处理方式一致。

callback 应改为:

function onRequestInputDataCallback() {
    return {
        cardholderInfo: {
            cardNumber: '4444333322221111',
            cardExpiryMonth: '07',
            cardExpiryYear: '24',
            cardholderName: 'Test Test',

            accountData: {
                emailAddress: 'test@test.com'
            },

            billingAddress: {
                streetAddress: 'X',
                city: 'X',
                state: 'X',
                country: 'AU',
                zipCode: '3000'
            }
        }
    };
}

原因

当前返回值的结构是:

{
    billingAddress: { /* ... */ },
    cardholderInfo: { /* ... */ },
    accountData: { /* ... */ }
}

这三个对象都在 callback 返回值的顶层。但从实际请求来看,NAB 的 JavaScript SDK 不会直接对整个返回值执行 JSON.stringify(),而是先提取它能识别的结构,再构造请求。

其处理过程相当于:

var input = onRequestInputDataCallback();

var requestData = {
    cardholderInfo: input.cardholderInfo
};

因此,最终只会保留 input.cardholderInfo。浏览器 Network 面板显示的是 SDK 实际发出的请求,不是显示错误。

文档表格将 cardholderInfo、accountData 和 billingAddress 标为 mandatory,并不表示它们一定处于同一级。PDF 中的缩进或层级关系很容易被忽略。这里需要满足的是 cardholderInfo 内部的数据结构。

推荐配置

还要确认 sp3dsConfig 引用的是修改后的 callback。问题中的配置使用了 onRequestInputDataCallback,示例函数名称却是 onRequestInputData。如果实际代码也有这一差异,SDK 调用的可能并不是预期函数。

function onRequestInputDataCallback() {
    return {
        cardholderInfo: {
            cardNumber: '4444333322221111',
            cardExpiryMonth: '07',
            cardExpiryYear: '24',
            cardholderName: 'Test Test',

            accountData: {
                emailAddress: 'test@test.com'
            },

            billingAddress: {
                streetAddress: '123 Test Street',
                city: 'Melbourne',
                state: 'VIC',
                country: 'AU',
                zipCode: '3000'
            }
        }
    };
}

var sp3dsConfig = {
    clientId: providerClientId,
    iframe: iframeElement,
    token: orderToken,
    simpleToken: simpleToken,
    threeDSSessionId: sessionId,
    onRequestInputData: onRequestInputDataCallback,
    onThreeDSResultsResponse: onThreeDSResultsResponseCallback,
    onThreeDSError: onThreeDSErrorCallback
};

修改后,Network 面板中的 data 应类似于:

{
  "cardholderInfo": {
    "cardNumber": "4444333322221111",
    "cardExpiryMonth": "07",
    "cardExpiryYear": "24",
    "cardholderName": "Test Test",
    "accountData": {
      "emailAddress": "test@test.com"
    },
    "billingAddress": {
      "streetAddress": "123 Test Street",
      "city": "Melbourne",
      "state": "VIC",
      "country": "AU",
      "zipCode": "3000"
    }
  }
}

关于错误码 180

修正对象层级后,如果仍然收到 180,需要继续逐项检查字段内容。仅凭这个错误码无法断定 3DS 服务不可用,因为 mandatory field 格式错误或银行卡不支持当前 3DS 流程,也可能触发该错误。

重点检查:

  • country 是否使用网关要求的国家代码,例如 AU,而不是国家全称。
  • state、zipCode 和地址字段是否符合 NAB 文档规定。
  • 卡号是否属于测试环境支持的卡品牌和测试卡范围。
  • cardExpiryMonth、cardExpiryYear 的长度是否符合当前接口要求。
  • token、simpleToken、clientId 和 threeDSSessionId 是否来自同一环境和同一次交易流程。
  • 页面加载的 securepay-threeds.js 与参考的 integration guide 是否为同一版本。

不要只看 callback 执行前的 console.log()。确认最终发送内容时,应以 Network 面板中的 request payload 为准。如果调整嵌套结构后,相关对象仍被 SDK 删除,就需要根据页面实际加载的 SDK 版本查阅对应文档,核对字段名称。NAB 的后续版本可能调整过数据模型。

备注:内容仅供参考。