为什么我的结账按钮和表单没有与条纹通信?



我的"提交(结账按钮(";转到我正在建设的电子商务网站的条纹结账页面。我遵循自定义付款流程想知道我是否可能错过了任何步骤?

我在下面提供了我的代码,其中包括server.js、checkout.js和index.html:

Server.js

const express = require("express");
const app = express();
// This is your test secret API key.
const stripe = require("stripe")('sk_test_XXXXXXXX');
app.use(express.static("public"));
app.use(express.json());
const calculateOrderAmount = (items) => {
[1, { priceInCents: 8500, name: "Black Sweatsuit"}],
[2, { priceInCents: 8500, name: "Grey Sweatsuit"}],
[3, { priceInCents: 8500, name: "Red Sweatsuit"}],
[4, { priceInCents: 8500, name: "Blue Sweatsuit"}]
return 1400;
};
app.post("/create-payment-intent", async (req, res) => {
const { items } = req.body;
// Create a PaymentIntent with the order amount and currency
const paymentIntent = await stripe.paymentIntents.create({
amount: calculateOrderAmount(items),
payment_method_types: ["card"],
mode: "payment", 
currency: "usd",
automatic_payment_methods: {
enabled: true,
},
});
// const endpointSecret = "whsec_93f2310c53f1bdbb9496049a38ea5ceadbce03fcf4223b2be51c5b6717f2cc60";
// app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
//   const sig = request.headers['stripe-signature'];

//   let event;

//   try {
//     event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
//   } catch (err) {
//     response.status(400).send(`Webhook Error: ${err.message}`);
//     return;
//   }

//   // Handle the event
//   switch (event.type) {
//     case 'payment_intent.succeeded':
//       const paymentIntent = event.data.object;
//       // Then define and call a function to handle the event payment_intent.succeeded
//       break;
//     // ... handle other event types
//     default:
//       console.log(`Unhandled event type ${event.type}`);
//   }
res.send({
clientSecret: paymentIntent.client_secret,
});
});
const endpointSecret = "whsec_93f2310c53f1bdbb9496049a38ea5ceadbce03fcf4223b2be51c5b6717f2cc60";
app.post('/webhook', express.raw({type: 'application/json'}), (request, response) => {
const sig = request.headers['stripe-signature'];
let event;
try {
event = stripe.webhooks.constructEvent(request.body, sig, endpointSecret);
} catch (err) {
response.status(400).send(`Webhook Error: ${err.message}`);
return;
}
// Handle the event
switch (event.type) {
case 'payment_intent.succeeded':
const paymentIntent = event.data.object;
// Then define and call a function to handle the event payment_intent.succeeded
break;
// ... handle other event types
default:
console.log(`Unhandled event type ${event.type}`);
}
// Return a 200 response to acknowledge receipt of the event
response.send();
});

app.listen(4242, () => console.log('Running on port 4242'));

checkout.js

// This is your test publishable API key.
const stripe = Stripe("pk_test_XXXXX");
// The items the customer wants to buy
const items =  [{ id: "Black Sweatsuit"}]
[{ id: "Grey Sweatsuit"}]
[{ id: "Red Sweatsuit"}]
[{ id: "Blue Sweatsuit"}];
let elements;
initialize();
checkStatus();
document
.querySelector("#payment-form")
.addEventListener("submit", handleSubmit);
// Fetches a payment intent and captures the client secret
async function initialize() {
const response = await fetch("/create-payment-intent", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ items }),
});
const { clientSecret } = await response.json();
const appearance = {
theme: 'stripe',
};
elements = stripe.elements({ appearance, clientSecret });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
// Make sure to change this to your payment completion page
return_url: "http://localhost:4242/checkout.html",
},
});
// This point will only be reached if there is an immediate error when
// confirming the payment. Otherwise, your customer will be redirected to
// your `return_url`. For some payment methods like iDEAL, your customer will
// be redirected to an intermediate site first to authorize the payment, then
// redirected to the `return_url`.
if (error.type === "card_error" || error.type === "validation_error") {
showMessage(error.message);
} else {
showMessage("An unexpected error occurred.");
}
setLoading(false);
}
// Fetches the payment intent status after payment submission
async function checkStatus() {
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
const { paymentIntent } = await stripe.retrievePaymentIntent(clientSecret);
switch (paymentIntent.status) {
case "succeeded":
showMessage("Payment succeeded!");
break;
case "processing":
showMessage("Your payment is processing.");
break;
case "requires_payment_method":
showMessage("Your payment was not successful, please try again.");
break;
default:
showMessage("Something went wrong.");
break;
}
}
// ------- UI helpers -------
function showMessage(messageText) {
const messageContainer = document.querySelector("#payment-message");
messageContainer.classList.remove("hidden");
messageContainer.textContent = messageText;
setTimeout(function () {
messageContainer.classList.add("hidden");
messageText.textContent = "";
}, 4000);
}
// Show a spinner on payment submission
function setLoading(isLoading) {
if (isLoading) {
// Disable the button and show a spinner
document.querySelector("#submit").disabled = true;
document.querySelector("#spinner").classList.remove("hidden");
document.querySelector("#button-text").classList.add("hidden");
} else {
document.querySelector("#submit").disabled = false;
document.querySelector("#spinner").classList.add("hidden");
document.querySelector("#button-text").classList.remove("hidden");
}
}

index.html

</div> 
<div class="subtotal">Subtotal: $0.00</div>
<form id="payment-form">
<input type="text" id="email" placeholder="Enter email address" />
<div id="payment-element">
<!--Stripe.js injects the Payment Element-->
</div>
<button id="submit">
<div class="spinner hidden" id="spinner"></div>
<span id="button-text">Checkout</span>
</button>
<div id="payment-message" class="hidden"></div>
</form>
</div>

我建议查看stripe.paymentIntents.create:您需要使用payment_method_typesautomatic_payment_methods,而不是两者都使用。

另外,在上述代码中,calculateOrderAmount将始终返回1400。这不应该在创建PaymentIntent和呈现PaymentElement时引起任何问题,但我只是想指出这一点。

编辑:我发现了更多的东西:

  • 在checkout.js中,items的语法不正确。应该有一组单独的开括号和闭括号,每个项目都应该用逗号分隔:
const items = [{ id: "Black Sweatsuit"},
{ id: "Grey Sweatsuit"},
{ id: "Red Sweatsuit"},
{ id: "Blue Sweatsuit"}];
  • 在server.js中,应该完全删除modemode仅适用于Stripe的Checkout产品。如上所述,PaymentIntent创建调用应该被编辑为也使用payment_method_typesautomatic_payment_methods,而不是两者都使用
  • 在index.html中,请确保包含以下脚本(这可能已经在您的文件中,位于您共享的代码之上(:
<script src="https://js.stripe.com/v3/"></script>
<script src="checkout.js" defer></script>

这假设checkout.js位于public文件夹中。

最新更新