代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<form id="payment-form" action="." method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="06dAlJhwvSjVK7u4CZcyAbsa9Ikn9EYsiFGxFpA8z3W2wsr0UMKb8KIxNmYbyFYg">
<p><label for="email">Email:</label> <input type="email" name="payment_email" value="paus@prositeportal.ru" class="form-control" autocomplete="off" id="email" readonly="readonly" required></p>
<p><label for="phone">International Phone:</label> <input type="tel" name="payment_phone" class="form-control" autocomplete="off" id="phone" placeholder="International Phone" required></p>
<p><label for="cardholder-name">Full Name:</label> <input type="text" name="payment_name" class="form-control" autocomplete="off" id="cardholder-name" placeholder="Full Name" required></p>
<p><label for="line1">Address Line 1:</label> <input type="text" name="payment_address1" class="form-control" autocomplete="off" id="line1" placeholder="Address 1" required></p>
<p><label for="line2">Address Line 2:</label> <input type="text" name="payment_address2" class="form-control" autocomplete="off" id="line2" placeholder="Address 2"></p>
<p><label for="city">City:</label> <input type="text" name="payment_city" class="form-control" autocomplete="off" id="city" placeholder="City" required></p>
<p><label for="state">State or Province:</label> <input type="text" name="payment_state" class="form-control" autocomplete="off" id="state" placeholder="State or Province" required></p>
<p><label for="country">2 Letter Country Code (<a href="https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements" target="_blank" rel="noopener noreferrer nofollow">Find Your Country Code</a>):</label> <input type="text" name="payment_country" class="form-control" autocomplete="off" id="country" maxlength="2" placeholder="Country Code" required></p>
<script nonce="tKD42vLlpXoOTvs+kP4PUQ==" src="https://hcaptcha.com/1/api.js" async defer></script>
<script nonce="tKD42vLlpXoOTvs+kP4PUQ==">
function onSubmit(token) {
if ( window.history.replaceState ) {
window.history.replaceState( null, null, window.location.href );
}
var form = document.getElementById("payment-form");
document.getElementById("card-button").disabled = true;
form.submit();
if (event.error) {
document.getElementById("card-button").disabled = false;
}
}
</script>
<label>
Credit or Debit Card:
</label>
<div id="card-element" class="form-control stripe_card_padding">
<!-- A Stripe Element will be inserted here. -->
</div>
<!-- Used to display form errors. -->
<div id="card-errors" class="stripe_card_errors" role="alert" ></div>
<!-- <div id="stripe-result-handler" class="is-hidden">
Success! Got token: <span class="result"></span>
</div> -->
<button
id="card-button"
type="submit"
class=" form-control payment_button h-captcha"
data-sitekey="8b425911-fa93-429c-a98c-4c56b93b6662"
data-callback="onSubmit"
>
Submit Payment
</button>
</form>
<script nonce="tKD42vLlpXoOTvs+kP4PUQ==" src="https://js.stripe.com/v3/"></script>
<script nonce="tKD42vLlpXoOTvs+kP4PUQ==">
// Create a Stripe client.
var stripe = Stripe("pk_test_tcuxCLB8Y8NN8H3OPcR6ALKh00UjP2WfYt");
// Create an instance of Elements.
var elements = stripe.elements();
var cardButton = document.getElementById("card-button");
var cardholderName = document.getElementById("cardholder-name");
//var cardElement = elements.create("card");
//var cardElement = elements.create("card");
//cardElement.mount("#card-element");
var line1 = document.getElementById("line1");
var line2 = document.getElementById("line2");
var city = document.getElementById("city");
var country = document.getElementById("country");
var email = document.getElementById("email");
var phone = document.getElementById("phone");
var state = document.getElementById("state");
var style = {
base: {
color: 'black',
iconColor: 'black',
fontSize: '15px',
fontFamily: '"Roboto", sans-serif',
fontSmoothing: 'antialiased',
'::placeholder': {
color: 'black',
},
},
invalid: {
color: '',
':focus': {
color: '',
},
},
};
var cardElement = elements.create('card', {style: style});
cardElement.mount('#card-element');
// Add an instance of the card Element into the `card-element` <div>.
// Handle real-time validation errors from the card Element.
cardElement.addEventListener("change", function (event) {
var displayError = document.getElementById("card-errors");
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = "";
}
});
// Handle form submission.
//.value.trim() || null is needed to change the form input to required/optional for data collection. Was originally .value only.
var form = document.getElementById("payment-form");
form.addEventListener("submit", function (event) {
event.preventDefault();
document.getElementById("card-button").disabled = true;
var billingInfo = {
billing_details: {
name: cardholderName.value.trim() || null,
address: {
line1: line1.value.trim() || null,
line2: line2.value.trim() || null,
city: city.value.trim() || null,
state: state.value.trim() || null,
country: country.value.trim() || null,
},
email: email.value,
phone: phone.value.trim() || null,
}
};
stripe.createPaymentMethod('card', cardElement, billingInfo).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById("card-errors");
errorElement.textContent = result.error.message;
document.getElementById("card-button").disabled = false;
} else {
// Send the token to your server.
//setTimeout(stripeSourceHandler(result.paymentMethod.id), 3000);
stripeSourceHandler(result.paymentMethod.id);
}
});
});
// Submit the form with the source ID.
function stripeSourceHandler(payment_method_id) {
var form = document.getElementById("payment-form");
var hiddenInput = document.createElement("input");
hiddenInput.setAttribute("type", "hidden");
hiddenInput.setAttribute("name", "PaymentMethod");
hiddenInput.setAttribute("value", payment_method_id);
form.appendChild(hiddenInput);
// Insert the source ID into the form so it gets submitted to the server
// Submit the form
form.submit();
}
</script>
https://jsfiddle.net/g5nkcL1u/
我正在尝试使用 hcaptcha 执行此操作:
https://docs.hcaptcha.com/invisible#automatically-bind-the-challenge-to-a-button
我正在尝试将其与条纹.js结合起来。
我认为问题与按钮的数据回调有关。由于有 2 个单独的表单.submit();在我的代码中,它不知道要运行哪一个。
我的问题是,如何将我的条纹 javascript 与我的 hcaptcha JavaScript 结合起来,让它们协同工作?
错误:
'没有这样的付款方式' -> 如果我使用 data-callback="stripeSourceHandler">
'无法识别的请求 URL (POST:/v1/payment_methods//attach)' ->如果我使用 data-callback="onSubmit">
我不相信这与我的服务器代码有任何关系。如果我删除客户端上的所有 hcaptcha 代码,则服务器端一切正常。如果我使用常规的 hcaptcha 复选框小部件而不是绑定到按钮,则一切正常,因为没有数据回调。但是我想将 hcaptcha 绑定到一个按钮,因为与复选框小部件相比,它的用户体验更好。
我在我的其他表单网页中使用 onSubmit 函数,并且 hcaptcha 工作正常,因为条纹不涉及其他表单网页。
其他想法:
onSubmit 不会调用创建 Stripe 付款方式的代码部分。让创建发生在它自己的函数中,如callStripe(),然后在验证码部分之后调用该支付方法创建函数。
调用 hcaptcha.render() 以显示验证码,然后创建付款方式并提交表单
什么实际上触发了验证码流?onSubmit
似乎没有任何与此明确相关的内容。否则,您应该能够将 3 个块的序列链接在一起:
- 允许 hcaptcha 绑定并调用
onSubmit
(或其他一些 函数),删除form.submit()
调用 - 拆分表单事件 处理程序回调到独立函数中,并在 验证码
stripeSourceHandler
应该已经称为 回调
请注意,您还需要确保在服务器端验证 hcaptca 结果。
另外,你没有递归问题吗?您的表单提交侦听器 (form.addEventListener("submit", ...)
) 最终调用stripeSourceHandler
它本身调用form.submit()
。