我正在遵循一些教程来实现stripe https://www.youtube.com/watch?v=DF68MNDxVwU&t=12211s和https://alterclass.io/tutorials/create-an-ecommerce-website-with-nextjs-and-stripe不幸的是,它们都是在stripe更新它们的文档之前完成的。我正在遵循这些,同时查看文档,试图让它工作,但我已经调试了20个小时,现在没有运气。
2题:
1.有人能帮我指出我做错了什么吗?
1.我找到的所有教程,而不是在stripe docs页面上,都使用了一个函数来将购物车中的物品发送到后端。stripe页面上的演练没有显示这个函数。有人知道这个函数在stripe docs中的什么位置吗?
我试着完全按照条纹演练显示的那样做,它至少会把我链接到另一个页面,但我不知道如何用它发送购物车中的物品。我会被重定向到一个空白屏幕
here is the error I am getting: error - StripeInvalidRequestError: Invalid integer: NaN at StripeError.generate (/Users/cameron/nextjs-amazon-clone/node_modules/stripe/lib/Error.js:38:16) at res.toJSON.then.StripeAPIError.message (/Users/cameronautism/nextjs-amazon-clone/node_modules/stripe/lib/StripeResource.js:190:35) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { type: 'StripeInvalidRequestError', raw: { code: 'parameter_invalid_integer', doc_url: 'https://stripe.com/docs/error-codes/parameter-invalid-integer', message: 'Invalid integer: NaN', param: 'line_items[0][price_data][unit_amount]', request_log_url: 'https://dashboard.stripe.com/test/logs/req_DZ6nOqke9AHTHi?t=1670342108', type: 'invalid_request_error', headers: { server: 'nginx', date: 'Tue, 06 Dec 2022 15:55:08 GMT', 'content-type': 'application/json', 'content-length': '369', connection: 'keep-alive', 'access-control-allow-credentials': 'true', 'access-control-allow-methods': 'GET, POST, HEAD, OPTIONS, DELETE', 'access-control-allow-origin': '', 'access-control-expose-headers': 'Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required', 'access-control-max-age': '300', 'cache-control': 'no-cache, no-store', 'idempotency-key': 'e9fdd45b-a707-4421-adfb-e327b7bef077', 'original-request': 'req_DZ6nOqke9AHTHi', 'request-id': 'req_DZ6nOqke9AHTHi', 'stripe-version': '2022-11-15', 'strict-transport-security': 'max-age=63072000; includeSubDomains; preload' }, statusCode: 400, requestId: 'req_DZ6nOqke9AHTHi' }, rawType: 'invalid_request_error', code: 'parameter_invalid_integer', doc_url: 'https://stripe.com/docs/error-codes/parameter-invalid-integer', param: 'line_items[0][price_data][unit_amount]', detail: undefined, headers: { server: 'nginx', date: 'Tue, 06 Dec 2022 15:55:08 GMT', 'content-type': 'application/json', 'content-length': '369', connection: 'keep-alive', 'access-control-allow-credentials': 'true', 'access-control-allow-methods': 'GET, POST, HEAD, OPTIONS, DELETE', 'access-control-allow-origin': '', 'access-control-expose-headers': 'Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required', 'access-control-max-age': '300', 'cache-control': 'no-cache, no-store', 'idempotency-key': 'e9fdd45b-a707-4421-adfb-e327b7bef077', 'original-request': 'req_DZ6nOqke9AHTHi', 'request-id': 'req_DZ6nOqke9AHTHi', 'stripe-version': '2022-11-15', 'strict-transport-security': 'max-age=63072000; includeSubDomains; preload' }, requestId: 'req_DZ6nOqke9AHTHi', statusCode: 400, charge: undefined, decline_code: undefined, payment_intent: undefined, payment_method: undefined, payment_method_type: undefined, setup_intent: undefined, source: undefined, page: '/api/checkout_sessions' } wait - compiling /... event - compiled client and server successfully in 684 ms (909 modules) error - StripeInvalidRequestError: Invalid integer: NaN at StripeError.generate (/Users/cameronautism/nextjs-amazon-clone/node_modules/stripe/lib/Error.js:38:16) at res.toJSON.then.StripeAPIError.message (/Users/cameronautism/nextjs-amazon-clone/node_modules/stripe/lib/StripeResource.js:190:35) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { type: 'StripeInvalidRequestError', raw: { code: 'parameter_invalid_integer', doc_url: 'https://stripe.com/docs/error-codes/parameter-invalid-integer', message: 'Invalid integer: NaN', param: 'line_items[0][price_data][unit_amount]', request_log_url: 'https://dashboard.stripe.com/test/logs/req_p7bQKyDNDYJcw3?t=1670342119', type: 'invalid_request_error', headers: { server: 'nginx', date: 'Tue, 06 Dec 2022 15:55:19 GMT', 'content-type': 'application/json', 'content-length': '369', connection: 'keep-alive', 'access-control-allow-credentials': 'true', 'access-control-allow-methods': 'GET, POST, HEAD, OPTIONS, DELETE', 'access-control-allow-origin': '', 'access-control-expose-headers': 'Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required', 'access-control-max-age': '300', 'cache-control': 'no-cache, no-store', 'idempotency-key': 'f982b912-71b7-4583-b1c4-1918d03b8968', 'original-request': 'req_p7bQKyDNDYJcw3', 'request-id': 'req_p7bQKyDNDYJcw3', 'stripe-version': '2022-11-15', 'strict-transport-security': 'max-age=63072000; includeSubDomains; preload' }, statusCode: 400, requestId: 'req_p7bQKyDNDYJcw3' }, rawType: 'invalid_request_error', code: 'parameter_invalid_integer', doc_url: 'https://stripe.com/docs/error-codes/parameter-invalid-integer', param: 'line_items[0][price_data][unit_amount]', detail: undefined, headers: { server: 'nginx', date: 'Tue, 06 Dec 2022 15:55:19 GMT', 'content-type': 'application/json', 'content-length': '369', connection: 'keep-alive', 'access-control-allow-credentials': 'true', 'access-control-allow-methods': 'GET, POST, HEAD, OPTIONS, DELETE', 'access-control-allow-origin': '', 'access-control-expose-headers': 'Request-Id, Stripe-Manage-Version, X-Stripe-External-Auth-Required, X-Stripe-Privileged-Session-Required', 'access-control-max-age': '300', 'cache-control': 'no-cache, no-store', 'idempotency-key': 'f982b912-71b7-4583-b1c4-1918d03b8968', 'original-request': 'req_p7bQKyDNDYJcw3', 'request-id': 'req_p7bQKyDNDYJcw3', 'stripe-version': '2022-11-15', 'strict-transport-security': 'max-age=63072000; includeSubDomains; preload' }, requestId: 'req_p7bQKyDNDYJcw3', statusCode: 400, charge: undefined, decline_code: undefined, payment_intent: undefined, payment_method: undefined, payment_method_type: undefined, setup_intent: undefined, source: undefined, page: '/api/checkout_sessions' }
下面是我后端代码
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
export default async function handler(req, res) {
const { items, email } = req.body;
const session = await stripe.checkout.sessions.create({
shipping_rates: ["shr_1MBn0HFqoomU2P4qZk4vqOQ3"],
shipping_address_collection: {
allowed_countries: ["US", "CA", "GB"],
},
line_items:[ { quantity: 1,
price_data: {
currency: 'usd',
unit_amount: items.price * 100,
product_data: {
description: items.description,
name: items.title,
}}}],
mode: 'payment',
success_url: `${process.env.HOST}/success`,
cancel_url: `${process.env.HOST}/checkout`,
metadata: {
email,
images: JSON.stringify(items.map(items => items.image))
}
});
res.status(200).JSON({ id:session.id});
};
下面是我前端:
正在使用该函数的按钮位于底部
import Header from "../public/components/Header";
import Image from "next/image";
import CheckoutProduct from "../public/components/CheckoutProduct";
import React, { useState, useEffect} from "react";
import { useSession } from "next-auth/react";
import { useAppContext } from "../public/state";
import { loadStripe } from "@stripe/stripe-js";
import { Elements } from "@stripe/react-stripe-js";
import axios from 'axios';
// import CheckoutForm from "../public/components/CheckoutForm";
const stripePromise = loadStripe(process.env.stripe_public_key);
function Checkout() {
const [basket, addToBasket] = useAppContext();
const { data: session } = useSession();
const itemsInBasketEqualToProducts = basket.map(item => item.price);
const sum = itemsInBasketEqualToProducts.reduce(
(accumulator, currentValue) => accumulator + currentValue,
0
);
const createCheckoutForm = async () => {
const stripe = await stripePromise;
//call the backend to create a checkout session...
const checkoutSession = await axios.post('/api/checkout_sessions',
{
items: basket,
email: session.user.email
})
const result = await stripe.redirectToCheckout({
sessionId: checkoutSession.data.id
});
if (result.error) {
alert(result.error.message)
};
};
return (
<div className="bg-gray-100">
<Header />
<main className="lg:flex max-w-screen-xl mx-auto">
{/* this is to test if the array of objects are being assigned correctly , this is also the proper way to satisfy react if you get the error objects are not valid as a react child*/}
{/* <div>
{basketItemsObject.map((item) => (
<p>{item.id}</p>
))}
</div> */}
{/* left*/}
<div className="flex-grow m-5 shadow-lg">
<Image
src="https://links.papareact.com/ikj"
width={2000}
height={250}
objectfit='contain'
/>
<div className="flex flex-col p-5 space-y-5 bg-white">
<h1 className="text-3xl border-b pb-4">
{/* {maybe} */}
{basket.length === 0 ? 'Your Basket is empty' : 'Shopping Basket'}
</h1>
<CheckoutProduct/>
</div>
</div>
{/* right */}
{/* subtotal */}
<div className=" bg-white shadow-lg flex">
{basket.length > 0 && (
<div className="">
<h2 className=" ">
Subtotal ({basket.length} items):
<span className="font-bold">
{sum}
</span>
</h2>
<button
onClick={createCheckoutForm}
type="submit"
role="link"
disabled={!session}
className={`button mt-2 ${
!session &&
` from-gray-300 to-gray-500 border-gray-200 text-gray-100 cursor-not-allowed`
}`}
>
{!session ? 'Sign in to checkout' : 'Proceed to checkout' }
</button>
</div>
)}
</div>
</main>
</div>
)
}
让我知道,如果有另一种方法,我应该格式化代码,使它更容易阅读!
1条答案
按热度按时间c0vxltue1#
因此,看起来您将
basket
(一个数组)作为items
传递给后端。如果您在该端点中所做的一切只是创建一个结帐会话,并在其中将向客户收取的费用的总和指定为unit_amount
,则实际上没有必要这样做。您已经在前端的一个变量中获得了总和:sum
。不必传递整个购物篮,只需将sum
从前端传递到后端,并使用unit_amount
创建checkout会话sum
* 100。但是,建议您将Price id的列表传递给Checkout Session,而不是从前端传递总计。这有助于防止数据被前端操作,并允许您跟踪客户在后端支付的确切项目(价格对象)。
编辑:如果您真的想采用内联指定price_data的方法,而不是传递price id(不推荐),那么看起来您还需要指定product_data,所以这可能就是为什么您所学习的教程将整个购物篮传递到后端的原因。在这种情况下,购物篮中的每一项都需要在Checkout Session上作为line_item传递。因此,您需要在后端操作items数组使其与Checkout期望的line_items数组格式相同。