const appearance = {
theme: 'night',
};
const stripe = Stripe('pk_test_51PccgFRo1v56iAOxEVEimciGkyyLOcjVE98T3rqOHLuvx28QNxI8sfvYN0zwSka8vLRIIIEdkOHorjb5OJUdwhIx00VRs64Seu');
// Set up Stripe Elements
const elements = stripe.elements({appearance: {theme: 'night'}});
const card = elements.create('card' );
card.mount('#payment-element');
document.querySelector("#payment-form").addEventListener("submit", async (event) => {
event.preventDefault();
document.getElementById('submit').disabled = true;
const name = document.querySelector("#name").value;
const email = document.querySelector("#email").value;
try {
// Create the customer by sending data to the server
const customerResponse = await fetch("http://localhost:4242/create-customer", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name, email }),
});
console.log(customerResponse);
// Ensure the response is JSON
if (!customerResponse.ok) {
throw new Error("Failed to create customer.");
}
const customerData = await customerResponse.json();
console.log("Customer created:", customerData);
// Create a token for the card details
const { token, error } = await stripe.createToken(card);
if (error) {
console.error('Error creating token:', error);
alert('Failed to tokenize card details. Please try again.');
document.getElementById('submit').disabled = false;
return;
}
// Proceed to initialize the payment process
await initializePayment(customerData.customerId, token.id);
} catch (error) {
document.querySelector("#error-message").textContent = error.message || "Failed to create customer.";
console.error("Error:", error);
document.getElementById('submit').disabled = false;
}
});
async function initializePayment(customerId, tokenId) {
try {
// Create the checkout session
const sessionResponse = await fetch("http://localhost:4242/create-checkout-session", {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
customer: customerId, // Pass the customer ID to backend
token: tokenId, // Pass the tokenized card ID to backend
priceId: 'price_1PfUDSRo1v56iAOxxLORAlv9'
})
});
if (!sessionResponse.ok) {
const errorData = await sessionResponse.json();
throw new Error(errorData.message || `Failed to create checkout session.`);
}
const sessionData = await sessionResponse.json();
window.location.href = sessionData.url; // Redirect to the Stripe Checkout or success page
} catch (error) {
document.querySelector("#error-message").textContent = error.message || "Failed to process payment.";
console.error('Error:', error);
} finally {
document.getElementById('submit').disabled = false;
}
}
public class Server {
private static final Gson gson = new Gson();
public static void main(String[] args) {
port(4242);
options("/*", (request, response) -> {
String accessControlRequestHeaders = request.headers("Access-Control-Request-Headers");
if (accessControlRequestHeaders != null) {
response.header("Access-Control-Allow-Headers", accessControlRequestHeaders);
}
String accessControlRequestMethod = request.headers("Access-Control-Request-Method");
if (accessControlRequestMethod != null) {
response.header("Access-Control-Allow-Methods", accessControlRequestMethod);
}
return "OK";
});
before((request, response) -> {
response.header("Access-Control-Allow-Origin", "*"); // Allow all origins
response.header("Access-Control-Allow-Headers", "*");
response.header("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
response.header("Access-Control-Allow-Credentials", "true");
});
// Set Stripe API keys directly in the code
Stripe.apiKey = "sk_test_yHMt2Vkexample";
// Domain URL
String domainUrl = "http://localhost:4242";
get("/config", (request, response) -> {
response.type("application/json");
Map<String, Object> responseData = new HashMap<>();
responseData.put("publishableKey", "pk_test_51PccgFRo1v56iAOxEVEimciGkyyLOcjVE98T3rqOHLuvx28QNxI8sfvYN0zwSka8vLRIIIEdkOHorjb5OJUdwhIx00VRs64Seu");
responseData.put("proPrice", "price_1PfUDSRo1v56iAOxxLORAlv9");
return gson.toJson(responseData);
});
// Fetch the Checkout Session to display the JSON result on the success page
get("/checkout-session", (request, response) -> {
response.type("application/json");
String sessionId = request.queryParams("sessionId");
Session session = Session.retrieve(sessionId);
return gson.toJson(session);
});
post("/create-customer", (request, response) -> {
response.type("application/json");
Map<String, Object> requestData = gson.fromJson(request.body(), Map.class);
String email = (String) requestData.get("email");
String name = (String) requestData.get("name");
try {
CustomerCreateParams params = CustomerCreateParams.builder()
.setEmail(email)
.setName(name)
.build();
Customer customer = Customer.create(params);
Map<String, Object> responseData = new HashMap<>();
responseData.put("customerId", customer.getId());
responseData.put("email", customer.getEmail());
responseData.put("name", customer.getName());
return gson.toJson(responseData);
} catch (StripeException e) {
response.status(400);
Map<String, Object> errorData = new HashMap<>();
errorData.put("error", e.getMessage());
return gson.toJson(errorData);
}
});
post("/create-checkout-session", (request, response) -> {
response.type("application/json");
// Parse request body as JSON
Map<String, Object> requestData = gson.fromJson(request.body(), Map.class);
// Retrieve the priceId from the JSON payload
String priceId = (String) requestData.get("priceId");
// Create session parameters
SessionCreateParams params = new SessionCreateParams.Builder()
.setSuccessUrl(domainUrl + "/success.html?session_id={CHECKOUT_SESSION_ID}")
.setCancelUrl(domainUrl + "/canceled.html")
.setMode(SessionCreateParams.Mode.SUBSCRIPTION)
.addLineItem(new SessionCreateParams.LineItem.Builder()
.setQuantity(1L)
.setPrice(priceId)
.build()
)
.build();
try {
Session session = Session.create(params);
response.status(303); // HTTP 303 See Other
response.redirect(session.getUrl());
return ""; // Returning an empty string to indicate no body content
} catch (Exception e) {
Map<String, Object> messageData = new HashMap<>();
messageData.put("message", e.getMessage());
Map<String, Object> responseData = new HashMap<>();
responseData.put("error", messageData);
response.status(400);
return gson.toJson(responseData);
}
});
post("/customer-portal", (request, response) -> {
String sessionId = request.queryParams("sessionId");
// Retrieve the Checkout Session to get the customer ID
Session checkoutSession;
try {
checkoutSession = Session.retrieve(sessionId);
} catch (Exception e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Failed to retrieve session: " + e.getMessage()));
}
String customer = checkoutSession.getCustomer();
// Create a Billing Portal session
com.stripe.param.billingportal.SessionCreateParams params =
new com.stripe.param.billingportal.SessionCreateParams.Builder()
.setReturnUrl(domainUrl + "/account") // Redirect to your account page after managing billing
.setCustomer(customer)
.build();
com.stripe.model.billingportal.Session portalSession;
try {
portalSession = com.stripe.model.billingportal.Session.create(params);
} catch (Exception e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Failed to create billing portal session: " + e.getMessage()));
}
// Redirect to the billing portal
response.redirect(portalSession.getUrl(), 303);
return "";
});
post("/webhook", (request, response) -> {
String payload = request.body();
String sigHeader = request.headers("Stripe-Signature");
String endpointSecret = "your_webhook_secret"; // Replace with your actual webhook secret
Event event;
try {
event = Webhook.constructEvent(payload, sigHeader, endpointSecret);
} catch (SignatureVerificationException e) {
response.status(400);
return gson.toJson(Collections.singletonMap("error", "Invalid signature"));
}
// Handle the event
switch (event.getType()) {
case "checkout.session.completed":
// Handle successful payment
System.out.println("Checkout Session completed: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "invoice.payment_succeeded":
// Handle successful payment for invoices
System.out.println("Invoice payment succeeded: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "invoice.payment_failed":
// Handle failed payment for invoices
System.out.println("Invoice payment failed: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "customer.subscription.created":
// Handle subscription creation
System.out.println("Subscription created: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
case "customer.subscription.deleted":
// Handle subscription cancellation
System.out.println("Subscription canceled: " + event.getDataObjectDeserializer().getObject().toString());
response.status(200);
break;
default:
response.status(200);
System.out.println("Unhandled event type: " + event.getType());
break;
}
return "";
});
}
}
所以这个错误是在执行initial payment函数时引起的,但是由于AWS的限制,stripe不接受OPTIONS请求,根据我的javascript,我可以做些什么来防止这种情况发生,因为我的应用程序在端口8443上运行。我可以看到客户创建发生在条带上,但无法付款。
您的后端代码尝试立即重定向到 Stripe Checkout URL :
response.status(303); // HTTP 303 See Other
response.redirect(session.getUrl());
但是你的前端代码期望从后端获取 JSON 并从中提取 URL 并在 JS 中重定向浏览器本身:
const sessionData = await sessionResponse.json();
window.location.href = sessionData.url; // Redirect to the Stripe Checkout or success page
从服务器使用 HTTP 3xx 进行重定向在 fetch/XHR 上下文中不起作用。
要解决此问题,您应该更改后端代码以返回前端期望的信息。
post("/create-checkout-session", (request, response) -> {
...
Session session = Session.create(params);
Map<String, String> responseData = new HashMap<>();
responseData.put("url", session.getUrl());
return gson.toJson(responseData);
...
}});
您的代码还有其他超出范围的问题,例如在同一页面上使用 CardElement 和 Checkout,这有点奇怪。