在 ReactTS 和 .Net 项目中集成 Stripe Checkout 的问题

Issue with integrating Stripe Checkout in ReactTS and .Net project

提问人:Snooper_A 提问时间:11/16/2023 最后编辑:Brian Tompsett - 汤莱恩Snooper_A 更新时间:11/17/2023 访问量:29

问:

我正在开发一个 React TypeScript 项目,该项目具有用于 API 服务的 ASP.NET 后端。我正在尝试按照此处的指南集成 Stripe Checkout。但是,我遇到了一个错误:

'price' 参数应该是价格对象的 ID,而不是文字数字价格。有关如何设置价格对象的详细信息,请参阅 https://stripe.com/docs/billing/prices-guide#create-prices

有关其他详细信息,我已使用 Context API 在用户将产品添加到购物车时进行状态管理。

这是我的前端代码:

import { useState } from "react";
import { useCart } from "../../context/cart-context";
import { Container, Button, Text, Group, Grid, Col, Divider } from "@mantine/core";
import { Image, Input } from "@mantine/core";
import { routes } from "../../routes";

export const CartPage = () => {
  const { cart, removeFromCart, updateCartItemQuantity } = useCart();
  const [isCheckout, setIsCheckout] = useState(false);

  const handleRemoveFromCart = (productId) => {
    removeFromCart(productId);
  };

  const handleQuantityChange = (productId, newQuantity) => {
    const itemToUpdate = cart.find((item) => item.product.id === productId);

    if (itemToUpdate) {
      updateCartItemQuantity(itemToUpdate.product.id, newQuantity);
    }
  };

  const calculateTotalPrice = (item) => {
    return item.product.price * item.quantity;
  };

  const calculateCartTotalPrice = () => {
    return cart.reduce((total, item) => total + calculateTotalPrice(item), 0).toFixed(2);
  };

  const handleCheckout = async () => {
    const cartItems = cart.map((item) => ({
      PriceId: item.product.price,
      quantity: item.quantity,
    }));

    try {
      const response = await fetch("https://localhost:44312/api/checkout/create-session", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(cartItems),
      });

      const data = await response.json();
      console.log("here is data",data);

      window.location.href = routes.home;
    } catch (error) {
      console.error("Error creating checkout session:", error);
    }
  };

  return (
    <Container>
      <h2>Your Cart</h2>
      {cart.length === 0 ? (
        <Container style={{ textAlign: "center" }}>
          <Text style={{ fontWeight: "bold" }}>Empty Cart</Text>
          <Text>Add products to your cart</Text>
        </Container>
      ) : (
        <>
          <Grid gutter="lg" style={{ fontWeight: "bold" }}>
            <Col span={3}>
              <Text>Product</Text>
            </Col>
            <Col span={3}>
              <Text>Quantity</Text>
            </Col>
            <Col span={3}>
              <Text>Price</Text>
            </Col>
            <Col span={3}>
              <Text>Action</Text>
            </Col>
          </Grid>
          <Divider my="sm" />

          {cart.map((item, index) => (
            <Container key={item.product.id}>
              <Grid gutter="lg">
                <Col span={3}>
                  <Group align="middle">
                    <Image
                      src={`data:image/jpeg;base64,${item.product.images[0].data}`}
                      alt="Product Image"
                      width={80}
                    />
                    <Text>{item.product.name}</Text>
                  </Group>
                </Col>
                <Col span={3}>
                  <Group align="middle">
                    <Button onClick={() => handleQuantityChange(item.product.id, item.quantity - 1)}>-</Button>
                    <Input
                      type="number"
                      value={item.quantity}
                      onChange={(event) =>
                        handleQuantityChange(item.product.id, parseInt(event.target.value))
                      }
                      min={1}
                    />
                    <Button onClick={() => handleQuantityChange(item.product.id, item.quantity + 1)}>+</Button>
                  </Group>
                </Col>
                <Col span={3}>
                  <Text>${(item.product.price * item.quantity).toFixed(2)}</Text>
                </Col>
                <Col span={3}>
                  <Button
                    onClick={() => handleRemoveFromCart(item.product.id)}
                    variant="outline"
                    color="red"
                  >
                    Remove
                  </Button>
                </Col>
              </Grid>
              {index < cart.length - 1 && <Divider size="xs" style={{ marginTop: '16px', marginBottom: '16px' }} />}
            </Container>
          ))}
          <Container style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <Text style={{ fontWeight: "bolder" }}>Total Price: ${calculateCartTotalPrice()}</Text>
            <Button variant="outline" color="yellow" onClick={() =>setIsCheckout(true)}>
              Checkout
            </Button>
          </Container>
          {isCheckout && handleCheckout()}
        </>
      )}
    </Container>
  );
};

export interface GetProduct {
    id: number;
    name: string;
    description: string;
    productCategories: string|null;
    price: number;
    status:string|null;
    images: Array<{ id: number; data: string }>;
  }
  

以下是我按照文档开发的 API:

using Entities;
using Microsoft.AspNetCore.Mvc;
using Stripe;
using Stripe.Checkout;
using System.Collections.Generic;
using System.Linq;

[Route("api/checkout")]
[ApiController]
public class CheckoutApiController : ControllerBase
{
    [HttpPost("create-session")]
    public ActionResult CreateCheckoutSession([FromBody] List<CartItem> cartItems)
    {
        var domain = "https://localhost:44312"; 
        var stripeSecretKey = "sk_test_51OB0nSH2tjloydjcsI57ff00Lc2Mkmpf";

        StripeConfiguration.ApiKey = stripeSecretKey;

        
        var options = new SessionCreateOptions
        {
            LineItems = cartItems.Select(item => new SessionLineItemOptions
            {
                Price = item.PriceId.ToString(), 
                Quantity = item.Quantity,
            }).ToList(),
            Mode = "payment",
            SuccessUrl = domain + "?success=true",
            CancelUrl = domain + "?canceled=true",
        };

        var service = new SessionService();
        Session session = service.Create(options);

        return Ok(new { sessionId = session.Id });
    }
}

public class CartItem
{
    public string PriceId { get; set; } 
    public int Quantity { get; set; }
}

我将价格修改为字符串,因为价格的数据类型是字符串。SessionLineItemOptions

我没有我的产品。stripePriceId

reactjs asp.net typescript stripe-payments

评论

0赞 LauraT 11/16/2023
我建议从上面的代码片段中删除您的测试密钥。虽然它是一个测试密钥,但你仍然应该保密/远离公共论坛。
0赞 Snooper_A 11/16/2023
@LauraT这只是随机密钥,我已经从我的 api 密钥中删除了这个密钥。
0赞 LauraT 11/16/2023
明白了。我建议记录您在 中使用的值。Stripe 需要格式为 的字符串 ID。根据错误消息,您似乎正在传递商品的数值/文字价格。由于您有一个价格 ID,因此应改为传递此 ID。PriceSessionCreateOptionsprice_123abc...
0赞 Snooper_A 11/16/2023
@LauraT我试过了,但犯了同样的错误,我的产品中没有stripePriceId。你能帮我解决这个问题吗?
0赞 LauraT 11/16/2023
哦,我完全误读了你的信息;您提到您没有价格 ID。虽然可以在 Checkout 中使用内联价格数据,但您以内联方式创建的任何价格和/或产品都不能重复使用。如果您预计以相同的金额向多个客户收取同一商品的费用,则应创建“产品”和“价格”,并使用“价格”传递价格 ID。如果您希望以内联方式创建价格,则应使用来传递货币、金额和产品(或用于创建内联产品)。SessionLineItemOptionsSessionLineItemPriceDataOptionsSessionLineItemPriceDataProductDataOptions

答: 暂无答案