- 集成指南
- 实施 Hosted Session 集成
实施 Hosted Session 集成
Hosted Session JavaScript 客户端库让您可以在付款单字段(由 QNB ALAHLI 托管)中从付款人处收集敏感付款详细信息。网关在付款会话中收集敏感的付款详细信息并暂时存储这些信息供以后使用。然后,您可以在交易请求中包括付款会话(代替付款详细信息)来处理付款。有关详细信息,请参阅付款会话。
Hosted Session 是一种 PCI v3 兼容的集成方法,可以促进 SAQ-A 合规,同时允许控制付款页面的布局和样式。在此模型中,全部敏感付款字段均嵌入到来自 QNB ALAHLI 并由其控制的内嵌框架中。标准浏览器的安全保护机制将敏感字段与您隔离,保留网关提供的支付同道的完整性。
先决条件
- 请确保已为 Hosted Session 服务启用商家配置文件。
- <<webServicesIntegration>> 版本 18 及更高版本仅支持 Hosted Session。
请求 Hosted Session 交互
此部分介绍为收集付款人的信用卡详细信息进行的 Hosted Session 简单集成。
<html> <head> <!-- INCLUDE SESSION.JS JAVASCRIPT LIBRARY --> <script src="https://qnbalahli.test.gateway.mastercard.com/form/version/72/merchant/<MERCHANTID>/session.js"></script> <!-- APPLY CLICK-JACKING STYLING AND HIDE CONTENTS OF THE PAGE --> <style id="antiClickjack">body{display:none !important;}</style> </head> <body> <!-- CREATE THE HTML FOR THE PAYMENT PAGE --> <div>Please enter your payment details:</div> <h3>Credit Card</h3> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="1" readonly></div> <div>Expiry Month:<input type="text" id="expiry-month" class="input-field" title="expiry month" aria-label="two digit expiry month" value="" tabindex="2" readonly></div> <div>Expiry Year:<input type="text" id="expiry-year" class="input-field" title="expiry year" aria-label="two digit expiry year" value="" tabindex="3" readonly></div> <div>Security Code:<input type="text" id="security-code" class="input-field" title="security code" aria-label="three digit CCV security code" value="" tabindex="4" readonly></div> <div>Cardholder Name:<input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="5" readonly></div> <div><button id="payButton" onclick="pay('card');">Pay Now</button></div> <!-- JAVASCRIPT FRAME-BREAKER CODE TO PROVIDE PROTECTION AGAINST IFRAME CLICK-JACKING --> <script type="text/javascript"> if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } PaymentSession.configure({ session: "<your_session_ID>", fields: { // ATTACH HOSTED FIELDS TO YOUR PAYMENT PAGE FOR A CREDIT CARD card: { number: "#card-number", securityCode: "#security-code", expiryMonth: "#expiry-month", expiryYear: "#expiry-year", nameOnCard: "#cardholder-name" } }, //SPECIFY YOUR MITIGATION OPTION HERE frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { // HANDLE INITIALIZATION RESPONSE }, formSessionUpdate: function(response) { // HANDLE RESPONSE FOR UPDATE SESSION if (response.status) { if ("ok" == response.status) { console.log("Session updated with data: " + response.session.id); //check if the security code was provided by the user if (response.sourceOfFunds.provided.card.securityCode) { console.log("Security code was provided."); } //check if the user entered a Mastercard credit card if (response.sourceOfFunds.provided.card.scheme == 'MASTERCARD') { console.log("The user entered a Mastercard credit card.") } } else if ("fields_in_error" == response.status) { console.log("Session update failed with field errors."); if (response.errors.cardNumber) { console.log("Card number invalid or missing."); } if (response.errors.expiryYear) { console.log("Expiry year invalid or missing."); } if (response.errors.expiryMonth) { console.log("Expiry month invalid or missing."); } if (response.errors.securityCode) { console.log("Security code invalid."); } } else if ("request_timeout" == response.status) { console.log("Session update failed with request timeout: " + response.errors.message); } else if ("system_error" == response.status) { console.log("Session update failed with system error: " + response.errors.message); } } else { console.log("Session update failed: " + response); } } }, interaction: { displayControl: { formatCard: "EMBOSSED", invalidFieldCharacters: "REJECT" } } }); function pay() { // UPDATE THE SESSION WITH THE INPUT FROM HOSTED FIELDS PaymentSession.updateSessionFromForm('card'); } </script> </body> </html>
步骤 1:创建会话
通过从您的服务器端应用程序提交 Create Session
请求来创建会话。请将会话身份验证限制指定为 25。响应将返回一个会话 ID,在后续步骤中您必须使用此 ID 来引用此会话。
URL | https://qnbalahli.test.gateway.mastercard.com/api/rest/version/72/merchant/<your_gateway_merchant_ID>/session |
HTTP 方法 | POST |
{ "session":{ "authenticationLimit":25 } }
步骤 2:更新会话中的订单金额和货币
通过从您的服务器端应用程序提交 Update Session
请求来更新会话,至少更新货币和订单金额。对于随后查询卡是否受支持以及是否需要卡安全码,此步骤是必需步骤。
URL | https://qnbalahli.test.gateway.mastercard.com/api/rest/version/72/merchant/<your_gateway_merchant_ID>/session/<your_session_ID> |
HTTP 方法 | PUT |
{ "order":{ "amount":100.00, "currency":"USD" } }
步骤 3:在付款页包含 session.js 客户端 JavaScript 库
通过在 head
元素内添加 script
元素,在付款页包含网关托管的 session.js
客户端 JavaScript 库。此文件的路径包括 api 版本和会话的商家识别码。这会将 PaymentSession
对象放入窗口名称空间。
<script type="text/javascript" src="https://qnbalahli.test.gateway.mastercard.com/form/version/72/merchant/<your_gateway_merchant_ID>/session.js"></script>
步骤 4:为包含信用卡字段的付款页创建 HTML
readonly
且不具有 name
属性。步骤 5:调用 PaymentSession.configure(configuration)
函数
configuration
对象允许您将托管字段附加到您的付款页和/或配置付款交互。您需要提供以下项:
- 包含在步骤 1:创建会话中创建的 session.id。
- 信用卡字段的字段选择器,如果提供将替换 QNB ALAHLI 托管的内嵌框架中嵌入的相应代理字段。代理字段具有与替换字段相同的外观。您可以捕获其他付款类型的付款详细信息,请参阅 Hosted Session 支持的付款方式。
-
阻止点阅绑架的缓解选项
点阅绑架又称“UI 纠正攻击”:用户打算点击最上层页面时,攻击者使用多个透明或不透明层欺骗用户点击另一页面上的按钮或链接。若要使用 Hosted Session,您必须实施以下针对点阅绑架攻击的一项或多项防范。
框架缓解选项 实施 javascript
在付款页中包括“框架式截断符”JavaScript。 x-frame-options
您的服务器应返回 X 框架选项 HTTP 响应标头。 csp
您的服务器应返回包含框架继承指令的 Content-Security-Policy HTTP 响应标头。 您必须指定通过
PaymentSession.configure(configuration)
调用中的frameEmbeddingMitigation
参数实施哪些防范。有关防范点阅绑架攻击的信息,请参阅 OWASP 外部网站的点阅绑架防范备忘单。 -
Hosted Session 交互期间处理各个事件的回调
initialized( )
:当托管字段附加到付款页时调用。formSessionUpdate( )
:在PaymentSession.updateSessionFromForm(paymentType)
函数的响应中调用(参见下一步)
步骤 6:调用 updateSessionFromForm
调用 PaymentSession.updateSessionFromForm('card')
,将捕获的付款类型 'card'
的付款详细信息存储到付款会话中。操作完成后,将调用 formSessionUpdate()
回调,其中包含结果参数。您必须检查 result.status
值以确定操作是否成功。请参见处理回调响应
步骤 7:使用付款会话数据
您可以使用返回的付款会话 (session.id) 来执行令牌化或付款交易(如果需要)。有关详细信息,请参见使用会话执行操作。
Hosted Session 支持的付款方式
Hosted Session 允许您配置以下一种或多种付款方式来从付款人处捕获付款详细信息。付款详细信息通过附加到您的付款单的托管字段捕获(安全钱包除外,其付款详细信息通过电子钱包交互捕获)。
您可以通过托管字段来捕获以下卡详细信息:
card.number
card.expiryMonth
card.expiryYear
card.securityCode
card.nameOnCard
card.expiryMonth
,那么 card.expiryYear
将是强制的,反之亦然。Hosted Session 允许您捕获通过 <<ach>> 直接付款(付款)和直接存款(退款)的详细信息。您可以通过托管字段来捕获以下 <<ach>> 详细信息:
ach.routingNumber
ach.bankAccountNumber
ach.bankAccountNumberConfirmation
ach.bankAccountHolder
ach.accountType
Hosted Session 允许您从电子钱包交互捕获付款详细信息。目前,仅支持 Secure Remote Commerce 电子钱包交互。您必须通过 QNB ALAHLI 进行 Secure Remote Commerce 启用才能发起此交互。请参见 Secure Remote Commerce。
字段数据验证反馈
Hosted Session 可让您在用户界面上的各个付款交互阶段向付款人提供验证反馈:
- 通过侦听
onValidityChange
回调在每次击键时:
PaymentSession.onValidityChange(["card.number", "card.nameOnCard"], function (selector, result) { if (result.isValid) { console.log("The field value is valid"); document.querySelector(selector).style.borderColor = "green"; } else if (result.isIncomplete) { console.log("The field value is not yet valid"); document.querySelector(selector).style.borderColor = "grey"; } else { console.log("The field value is invalid"); document.querySelector(selector).style.borderColor = "red"; } });
- 付款人完成键入,离开字段后:
- 侦听
onBlur()
事件 - 调用
validate()
- 显示
validate()
回调中该字段的所有错误
PaymentSession.onBlur( ["card.number", "card.nameOnCard", "card.securityCode", "card.expiryYear", "card.expiryMonth"], function (selector, role) { PaymentSession.validate('card', function (allresult) { if (allresult.card[role].isValid) { console.log("The field is valid"); document.querySelector(selector).style.borderColor = "green"; } else { console.log("The field is invalid"); document.querySelector(selector).style.borderColor = "red"; } }); });
- 侦听
- 当付款人单击页面的下一个操作按钮时:
- 调用
updateSessionFromForm()
- 显示
formSessionUpdate
回调中的所有错误
- 调用
无论采用哪种方法,都必须预期 formSessionUpdate
回调中有错误并进行处理。虽然 validate()
方法可能指示有效,但 formSessionUpdate
验证更为全面,可能检测到其他错误。
处理回调响应
initialized(result)
的托管字段的结果result.status=="ok"
托管字段将成功附加到您的付款页。
// An ok response { "status":"ok", }
result.status=="system_error"
或 result.status=="request_timeout"
附加托管字段时出错。您应该在短时间后重试。
// An error response (system_error) { "status": "system_error", "message": "System error message." } // An error response (request_timeout) { "status" : "request_timeout", "message": "Request timeout error message." }
formSessionUpdate(result)
的 Update Session 的结果result.status=="ok"
此会话现在包含收集的卡详细信息。
// An ok response { "status":"ok", "merchant": "TESTMERCHANT", "session": { "id": "SESSION000218450948092491657986" "updateStatus":"SUCCESS", "version":"e3f144ce02" }, "sourceOfFunds": { "provided": { "card": { "brand": "MASTERCARD", "expiry": { "month": "1", "year": "39" }, "fundingMethod": "DEBIT", "nameOnCard": "John Smith", "number": "512345xxxxxx8769", "scheme": "MASTERCARD" } }, "type": "CARD" }, "version": "43" }
result.status=="fields_in_error"
付款人输入无效,您应该提示付款人更新输入的信息。errors
响应结构包含有关无效字段的信息。
// An error response (fields_in_error) { "status": "fields_in_error", "session": { "id": "SESSION000218450948092491657986" }, "errors": { "cardNumber": "invalid", "securityCode": "invalid" }, version: "43" }
result.status=="system_error"
或 result.status=="request_timeout"
处理更新时发生错误。您应该在短时间后重试会话更新。
// An error response (system_error) { "status": "system_error", "session": { "id": "SESSION000218450948092491657986" }, "errors": { "message": "System error message." }, "version": "43" } // An error response (request_timeout) { "status" : "request_timeout", "session": { "id": "SESSION000218450948092491657986" }, "errors": { "message": "Request timeout error message." }, "version": "43" }
侦听托管字段的事件
Hosted Session 允许您注册回叫功能来处理付款人交互期间托管字段中可能发生的事件。
onChange( )
:在内嵌框架托管字段内的输入值更改时调用。onFocus( )
:在内嵌框架中的托管字段获得焦点时调用。onBlur( )
:在内嵌框架中的托管字段失去焦点时调用。onMouseOver( )
:当鼠标置于托管字段中发生的事件时调用。onMouseOut( )
:当鼠标从托管字段中发生的事件上移开时调用。
/** * Provide an array of field roles for proxy fields as the first parameter * Each callback function is invoked with the selector for the field whose proxy triggered the event. */ PaymentSession.onBlur(['card.number'], function(selector) { //handle blur event }); PaymentSession.onFocus(['card.number', 'card.securityCode'], function(selector) { //handle focus event }); PaymentSession.onChange(['card.securityCode'], function(selector) { //handle change event }); PaymentSession.onMouseOver(['card.number'], function(selector) { //handle mouse over event }); PaymentSession.onMouseOut(['card.number'], function(selector) { //handle mouse out event });
托管字段的高级样式
Hosted Session 允许您调整托管字段的样式,以匹配您的付款页中替换字段的外观和感觉。
setFocus( )
:在指定的托管字段中设置焦点。setFocusStyle( )
:在获得焦点时设置指定托管字段的样式属性。setHoverStyle( )
:在出现鼠标悬停时设置指定托管字段的样式属性。setPlaceholderStyle( )
:为指定托管字段的占位符文本设置样式属性。setPlaceholderShownStyle( )
:设置占位符文本可见时指定托管字段的样式属性。
PaymentSession.setFocus('card.number'); PaymentSession.setFocusStyle(["card.number","card.securityCode"], { borderColor: 'red', borderWidth: '3px' }); PaymentSession.setHoverStyle(["card.number","card.securityCode"], { borderColor: 'red', borderWidth: '3px' }); PaymentSession.setPlaceholderStyle(["card.number", "card.nameOnCard"], { color: 'blue', fontWeight: 'bold', textDecoration: 'underline' }); PaymentSession.setPlaceholderShownStyle(["card.number", "card.nameOnCard"], { color: 'green', fontWeight: 'bold', textDecoration: 'underline' });
过期月份和年份下拉字段
Hosted Session 允许您使用下拉值选择过期月份和过期年份。请参见下方的示例代码了解详细信息。
<html> <head> <!-- INCLUDE SESSION.JS JAVASCRIPT LIBRARY --> <script src="https://qnbalahli.test.gateway.mastercard.com/form/version/72/merchant/<MERCHANTID>/session.js"></script> <!-- APPLY CLICK-JACKING STYLING AND HIDE CONTENTS OF THE PAGE --> <style id="antiClickjack">body{display:none !important;}</style> </head> <body> <!-- CREATE THE HTML FOR THE PAYMENT PAGE --> <div>Please enter your payment details:</div> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="1" readonly></div> <div>Expiry Month: <select id="expiry-month" class="form-control input-md" required="" readonly> <option value="">Select Month</option> <option value="01">January</option> <option value="02">February</option> <option value="03">March</option> <option value="04">April</option> <option value="05">May</option> <option value="06">June</option> <option value="07">July</option> <option value="08">August</option> <option value="09">September</option> <option value="10">October</option> <option value="11">November</option> <option value="12">December</option> </select> </div> <div>Expiry Year: <select id="expiry-year" class="form-control input-md" required="" readonly> <option value="">Select Year</option> <option>21</option> <option>22</option> <option>23</option> <option>24</option> <option>25</option> <option>26</option> <option>27</option> <option>28</option> <option>29</option> <option>30</option> <option>31</option> <option>32</option> <option>33</option> <option>34</option> <option>35</option> <option>36</option> <option>37</option> <option>38</option> <option>39</option> </select> </div> <div>Security Code:<input type="text" id="security-code" class="input-field" title="security code" aria-label="three digit CCV security code" value="" tabindex="4" readonly></div> <div>Cardholder Name:<input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="3" readonly></div> <div><button id="payButton" onclick="pay();">Pay Now</button></div> <!-- JAVASCRIPT FRAME-BREAKER CODE TO PROVIDE PROTECTION AGAINST IFRAME CLICK-JACKING --> <script type="text/javascript"> if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } var sessions = []; PaymentSession.configure({ fields: { // ATTACH HOSTED FIELDS TO YOUR PAYMENT PAGE FOR A CREDIT CARD card: { number: "#card-number", securityCode: "#security-code", expiryMonth: "#expiry-month", expiryYear: "#expiry-year", nameOnCard: "#cardholder-name" } }, //SPECIFY YOUR MITIGATION OPTION HERE frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { // HANDLE INITIALIZATION RESPONSE }, formSessionUpdate: function(response) { // HANDLE RESPONSE FOR UPDATE SESSION if (response.status) { if ("ok" == response.status) { console.log("Session updated with data: " + response.session.id); //check if the security code was provided by the user if (response.sourceOfFunds.provided.card.securityCode) { console.log("Security code was provided."); } //check if the user entered a Mastercard credit card if (response.sourceOfFunds.provided.card.scheme == 'MASTERCARD') { console.log("The user entered a Mastercard credit card.") } } else if ("fields_in_error" == response.status) { console.log("Session update failed with field errors."); if (response.errors.cardNumber) { console.log("Card number invalid or missing."); } if (response.errors.expiryYear) { console.log("Expiry year invalid or missing."); } if (response.errors.expiryMonth) { console.log("Expiry month invalid or missing."); } if (response.errors.securityCode) { console.log("Security code invalid."); } } else if ("request_timeout" == response.status) { console.log("Session update failed with request timeout: " + response.errors.message); } else if ("system_error" == response.status) { console.log("Session update failed with system error: " + response.errors.message); } } else { console.log("Session update failed: " + response); } } }, interaction: { displayControl: { formatCard: "EMBOSSED", invalidFieldCharacters: "REJECT" } } }); function pay() { // UPDATE THE SESSION WITH THE INPUT FROM HOSTED FIELDS PaymentSession.updateSessionFromForm('card'); } </script> </body> </html>
配置托管字段的可访问性
Hosted Session 提供了可以提高您的网站的可访问性的功能。
<!-- CREATE THE HTML FOR THE PAYMENT PAGE --> <div>Please enter your payment details:</div> <div>Cardholder Name: <input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="1" readonly></div> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="2" readonly></div> <div>Expiry Month:<input type="text" id="expiry-month" class="input-field" title="expiry month" aria-label="two digit expiry month" value="" tabindex="3" readonly></div> <div>Expiry Year:<input type="text" id="expiry-year" class="input-field" title="expiry year" aria-label="two digit expiry year" value="" tabindex="4" readonly></div> <div>Security Code:<input type="text" id="security-code" class="input-field" title="security code" aria-label="card security code" value="" tabindex="5" readonly></div> <div><button id="payButton" onclick="pay();">Pay Now</button></div>
以下选项让您可以更好地控制具有可访问性需求的付款人的用户体验:
设置内嵌框架标题
托管字段的内嵌框架标题属性可以使用字段中的标题属性进行控制。
设置可访问性富互联网应用程序属性
Hosted Session 支持 aria 属性,您可以用它来增强使用辅助技术的付款人的体验。
设置无效字符显示参数
应考虑接受托管字段中的所有字符,以改进使用辅助技术的付款人的体验。为此,请在 PaymentSession.configure()
方法中设置显示参数 interaction.displayControl.invalidFieldCharacters=ALLOW
。
设置 lang
属性
将语言属性添加到 html 元素中。
<html lang="en"> <head></head> <body></body> </html>
隐藏的标签和错误消息
所有托管字段均包含隐藏标签,强制托管字段包含隐藏的错误消息。调用 PaymentSession.updateSessionFromForm()
产生的任何错误都会引出错误消息标签。您可以另外使用 PaymentSession.setMessage()
方法来引出您自己的错误。
例如,卡号字段的隐藏标签为“卡号”。缺少卡号的隐藏的错误消息是“缺少卡号,请输入值”。无效卡号的隐藏的错误消息是“卡号无效,请输入正确的值”。在托管字段之间切换时,屏幕阅读器仅读取隐藏的标签和隐藏的错误消息,而不会读取 UI 上显示的实际标签或错误消息。
在配置对象中设置区域设置属性
区域设置属性为所有托管字段提供翻译,包括隐藏的标签和错误消息。如果未设置,将默认为英语。此属性支持的值有 de_DE、el_GR、en_US、es_MX、es_ES、fr_CA、fr_FR、it_IT、ja_JA、pl_PL、pt_BR、ro_RO、zh_CN。
为避免对付款人造成混淆,建议语言属性与区域设置属性匹配。
PaymentSession.configure({ fields: { card: { nameOnCard: cardHolderNameField ? "#card-holder-name" : null, number: "#card-number", securityCode: "#security-code", expiryMonth: "#expiry-month", expiryYear: "#expiry-year" } }, frameEmbeddingMitigation: ["javascript"], locale:"fr", callbacks: { } });
自动焦点
默认的 HTML5 功能中有一个不适用于托管字段,即,当付款人单击标签时,它不会将焦点自动置于相应的输入/选择元素。请使用 setFocus
实现此目的。
通过 Hosted Session 接受多个卡
Hosted Session 让您可以在同一个页面上接受付款人的多个卡。在这种情况下,每个卡成为单独的付款会话和单独的订单(当您在付款交易中使用付款会话时)。举例来说,当客户希望能够在同一个预订中使用多个卡付款时,这项功能可能很有用。然后,您的网站必须能够将各个单独付款会话生成的这些订单集合到客户的一个预订中。
请求多 Hosted Session 交互
若要接受多个卡,您必须使用 scope
参数调用 PaymentSession.configure()
函数。此参数可以是用于识别卡付款数据块的任何一个唯一字符串,不需要在页面上引用任何特定的 html。您在商家服务器上为每个卡存储的数据应保存在单独的范围内。
PaymentSession.configure('configuration', scope)
在使用 scope
调用初始 PaymentSession.configure()
调用后,以下 Hosted Session 调用中的 scope
参数将成为强制的。
PaymentSession.updateSessionFromForm('card', 'card-type', scope)
PaymentSession.setFocus('cardNumber', scope)
如果使用范围配置了交互,以下调用中的 scope
参数则是可选的。如果未在调用中指定范围,函数/回调将应用于托管内嵌框架内的所有卡数据集。
PaymentSession.setFocusStyle([<HostedFieldsRole>], styles, scope)
PaymentSession.setHoverStyle([<HostedFieldsRole>], styles, scope)
PaymentSession.onFocus([<HostedFieldsRole>],function(selector), scope)
PaymentSession.onBlur([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onChange([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onMouseOver([<HostedFieldsRole>], function(selector), scope)
PaymentSession.onMouseOut([<HostedFieldsRole>], function(selector), scope)
示例
<html> <head> <!-- INCLUDE SESSION.JS JAVASCRIPT LIBRARY --> <script src="https://qnbalahli.test.gateway.mastercard.com/form/version/72/merchant/<MERCHANTID>/session.js"></script> <!-- APPLY CLICK-JACKING STYLING AND HIDE CONTENTS OF THE PAGE --> <style id="antiClickjack">body{display:none !important;}</style> </head> <body> <!-- CREATE THE HTML FOR THE PAYMENT PAGE --> <div>Please enter your payment details:</div> <div>Cardholder Name: <input type="text" id="cardholder-name" class="input-field" title="cardholder name" aria-label="enter name on card" value="" tabindex="1" readonly></div> <div>Card Number: <input type="text" id="card-number" class="input-field" title="card number" aria-label="enter your card number" value="" tabindex="2" readonly></div> <div>Expiry Month:<input type="text" id="expiry-month" class="input-field" title="expiry month" aria-label="two digit expiry month" value="" tabindex="3" readonly></div> <div>Expiry Year:<input type="text" id="expiry-year" class="input-field" title="expiry year" aria-label="two digit expiry year" value="" tabindex="4" readonly></div> <div>Security Code:<input type="text" id="security-code" class="input-field" title="security code" aria-label="three digit CCV security code" value="" tabindex="5" readonly></div> <div><button id="payButton" onclick="pay();">Pay Now</button></div> <!-- JAVASCRIPT FRAME-BREAKER CODE TO PROVIDE PROTECTION AGAINST IFRAME CLICK-JACKING --> <script type="text/javascript"> if (self === top) { var antiClickjack = document.getElementById("antiClickjack"); antiClickjack.parentNode.removeChild(antiClickjack); } else { top.location = self.location; } var sessions = []; PaymentSession.configure({ fields: { // ATTACH HOSTED FIELDS TO YOUR PAYMENT PAGE FOR A CREDIT CARD card: { number: "#card-number", securityCode: "#security-code", expiryMonth: "#expiry-month", expiryYear: "#expiry-year", nameOnCard: "#cardholder-name" } }, //SPECIFY YOUR MITIGATION OPTION HERE frameEmbeddingMitigation: ["javascript"], callbacks: { initialized: function(response) { // HANDLE INITIALIZATION RESPONSE }, formSessionUpdate: function(response) { // HANDLE RESPONSE FOR UPDATE SESSION AS PER USUAL MANNER. if (response.status) { if ("ok" == response.status) { // RECORD THE SESSIONID RETURNED AND ASSOCIATE IT WITH THE SCOPE CONFIGURED. sessions.push(JSON.parse('{ "scopeId": "' + response.scopeId + '", "sessionId": "' + response.session.id + '"}')); } } else { console.log("Session update failed: " + response); } } }, interaction: { displayControl: { formatCard: "EMBOSSED", invalidFieldCharacters: "REJECT" } } }, 'card-payment-details-#1'); // ADD ANY UNIQUE STRING IDENTIFIER VALUE TO THE CONFIGURE CALL function pay() { sessions.forEach(function (e) { // UPDATE THE SESSION WITH THE FIELD VALUES. THE SCOPE MUST BE THE THIRD PARAMETER. PaymentSession.updateSessionFromForm('card', undefined, e.scopeId); }); } </script> </body> </html>
测试您的集成
在投入使用前,您必须测试您的集成以确保功能正确。
若要在测试 Hosted Session 集成(使用 TEST 商家 ID)时支持额外的记录,将 ?debug=true
附加到 URL 中。
https://qnbalahli.test.gateway.mastercard.com/form/version/72/merchant/<TESTMERCHANTID>/session.js?debug=true
疑难解答和常见问题
若要处理此事件,请参考 PaymentSession.updateSessionFromForm('card')
响应中的卡类型信息(sourceOfFunds.provided.card.brand
和 sourceOfFunds.provided.card.scheme
),查看支持的卡类型的列表,如果卡类型不被接受则显示错误消息。
如果付款人未提供 CSC/CVV,securityCode
字段不会在 PaymentSession.updateSessionFromForm('card')
响应中返回。如果您需要 CSC/CVV 但未呈现值,那么您应该向付款人显示错误。
以下操作系统和浏览器存在已知的事件回调问题:
- Windows 10 中的 Internet Explorer 11:如果
interaction.displayControl.formatCard=EMBOSSED
,在更改托管字段的值时不触发onChange
事件。 - iPhone 6+ 中的 iOS9:当付款人在托管字段中输入数据并触碰付款页的另一个字段时,不触发
onChange( )
和onBlur( )
事件。此外,付款人还无法从托管字段导航至付款页的其他字段,反之亦然。
从 API 版本 51 开始,您可以在 Hosted Session 交互中收集一个或多个信用卡的付款详细信息。这样,付款人可以使用多个信用卡为一个预订付款;不过,由于每个卡的付款详细信息生成一个单独的订单,您需要负责将这些单独订单集合到付款人的一个预订中。
将为每个卡创建一个唯一的会话标识符,您必须将这些标识符存储在 Web 服务器上。付款人可以选择在交互期间移除卡,此操作将从您的 Web 服务器上删除与该卡关联的会话数据。
<<hostedPaymentForm>> POST 模式已被 Hosted Session JavaScript (session.js) 集成弃用。