未捕获(承诺中)IntegrationError:stripe.confirmCardPayment 意图秘密的值无效

问题描述 投票:0回答:3

尝试使用 stripe 结账时出现此错误:

未捕获(承诺中)IntegrationError:stripe.confirmCardPayment 意图机密的值无效:值应该是 ${id}secret${secret} 形式的客户端机密。您指定:.....

我在我的网站上使用了 stripe,并使用 firebase 函数实现了它。当我在本地运行我的网站和 firebase 功能时,我没有收到此错误,但是当我将其放在我的 firebase 托管上时,它不起作用,并且收到该错误。在本地,我将运行这些命令:

npm start
启动网站,然后在函数文件夹中进行 cd 操作,然后运行
npm run serve
。我怎样才能解决这个问题? 这是使用 firebase 函数运行的 index.js 文件: index.js

const functions = require('firebase-functions');
const express = require('express');
const cors = require('cors');
const stripe = require('stripe')(secret_key)
const app = express();
app.use(cors({
    origin: true
}));
app.use(express.json());

app.post('/payments/create', async (req, res) => {
    try {
        const { amount, shipping } = req.body;
        const paymentIntent = await stripe.paymentIntents.create({
            shipping,
            amount,
            currency: 'eur'
        });

        res
        .status(200)
        .send(paymentIntent.client_secret);
    }catch(err) {
        res
        .status(500)
        .json({
            statusCode: 500,
            message: err.message
        });
    }
})

app.get('*', (req, res) => {
    res
    .status(404)
    .send('404, Not Found');
});

exports.api = functions.https.onRequest(app);

这是package.json

  {
"name": "evelinas-art-store",
"version": "0.1.0",
"private": true,
"dependencies": {
  "@material-ui/core": "^4.11.2",
  "@stripe/react-stripe-js": "^1.1.2",
  "@stripe/stripe-js": "^1.11.0",
  "@testing-library/jest-dom": "^5.11.6",
  "@testing-library/react": "^11.2.2",
  "@testing-library/user-event": "^12.6.0",
  "axios": "^0.21.1",
  "ckeditor4-react": "^1.3.0",
  "firebase": "^8.2.1",
  "moment": "^2.29.1",
  "node-sass": "^4.14.1",
  "react": "^17.0.1",
  "react-country-region-selector": "^3.0.1",
  "react-dom": "^17.0.1",
  "react-redux": "^7.2.2",
  "react-router-dom": "^5.2.0",
  "react-scripts": "4.0.1",
  "redux": "^4.0.5",
  "redux-logger": "^3.0.6",
  "redux-persist": "^6.0.0",
  "redux-saga": "^1.1.3",
  "redux-thunk": "^2.3.0",
  "reselect": "^4.0.0",
  "web-vitals": "^0.2.4"
},
"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject"
},
"eslintConfig": {
  "extends": [
    "react-app",
    "react-app/jest"
  ]
},
"browserslist": {
  "production": [
    ">0.2%",
    "not dead",
    "not op_mini all"
  ],
  "development": [
    "last 1 chrome version",
    "last 1 firefox version",
    "last 1 safari version"
  ]
 }
}

有条纹付款的文件

  import React, { useState, useEffect } from 'react';
  import { CardElement, useStripe, useElements } from '@stripe/react-stripe-js';
  import FormInput from './../forms/FormInput';
  import Button from './../forms/Button';
  import { CountryDropdown } from 'react-country-region-selector';
  import { apiInstance } from './../../Utils';
  import { selectCartTotal, selectCartItemsCount, selectCartItems } from './../../redux/Cart/cart.selectors';
  import { saveOrderHistory } from './../../redux/Orders/orders.actions';
  import { createStructuredSelector } from 'reselect';
  import { useSelector, useDispatch } from 'react-redux';
  import { useHistory } from 'react-router-dom';
  import './styles.scss';

  const initialAddressState = {
    line1: '',
    line2: '',
    city: '',
    state: '',
    postal_code: '',
    country: '',
  };

  const mapState = createStructuredSelector({
    total: selectCartTotal,
    itemCount: selectCartItemsCount,
    cartItems: selectCartItems,
  });

  const PaymentDetails = () => {
    const stripe = useStripe();
    const elements = useElements();
    const history = useHistory();
    const { total, itemCount, cartItems } = useSelector(mapState);
    const dispatch = useDispatch();
    const [billingAddress, setBillingAddress] = useState({ ...initialAddressState });
    const [shippingAddress, setShippingAddress] = useState({ ...initialAddressState });
    const [recipientName, setRecipientName] = useState('');
     const [nameOnCard, setNameOnCard] = useState('');

    useEffect(() => {
      if (itemCount < 1) {
        history.push('/dashboard');
      }

    }, [itemCount]);

    const handleShipping = evt => {
      const { name, value } = evt.target;
      setShippingAddress({
        ...shippingAddress,
        [name]: value
      });
    };

    const handleBilling = evt => {
      const { name, value } = evt.target;
      setBillingAddress({
        ...billingAddress,
        [name]: value
      });
    }

    const handleFormSubmit = async evt => {
      evt.preventDefault();
      const cardElement = elements.getElement('card');

      if (
        !shippingAddress.line1 || !shippingAddress.city ||
        !shippingAddress.state || !shippingAddress.postal_code ||
        !shippingAddress.country || !billingAddress.line1 ||
        !billingAddress.city || !billingAddress.state ||
        !billingAddress.postal_code || !billingAddress.country ||
        !recipientName || !nameOnCard
      ) {
        return;
      }

      apiInstance.post('/payments/create', {
        amount: total * 100,
        shipping: {
          name: recipientName,
          address: {
            ...shippingAddress
          }
        }
      }).then(({ data: clientSecret }) => {

        stripe.createPaymentMethod({
          type: 'card',
          card: cardElement,
          billing_details: {
            name: nameOnCard,
            address: {
              ...billingAddress
            }
          }
        }).then(({ paymentMethod }) => {

          stripe.confirmCardPayment(clientSecret, {
            payment_method: paymentMethod.id
          })
          .then(({ paymentIntent }) => {

            const configOrder = {
              orderTotal: total,
              orderItems: cartItems.map(item => {
                const { documentID, productThumbnail, productName,
                  productPrice, quantity } = item;

                return {
                  documentID,
                  productThumbnail,
                  productName,
                  productPrice,
                  quantity
                };
              })
            }

            dispatch(
              saveOrderHistory(configOrder)
            );
          });

        })


      });

    };

    const configCardElement = {
      iconStyle: 'solid',
      style: {
        base: {
          fontSize: '16px'
        }
      },
      hidePostalCode: true
    };

    return (
      <div className="paymentDetails">
        <form onSubmit={handleFormSubmit}>

          <div className="group">
            <h2>
              Shipping Address
            </h2>

            <FormInput
              required
              placeholder="Recipient Name"
              name="recipientName"
              handleChange={evt => setRecipientName(evt.target.value)}
              value={recipientName}
              type="text"
            />

            <FormInput
              required
              placeholder="Line 1"
              name="line1"
              handleChange={evt => handleShipping(evt)}
              value={shippingAddress.line1}
              type="text"
            />

            <FormInput
              placeholder="Line 2"
              name="line2"
              handleChange={evt => handleShipping(evt)}
              value={shippingAddress.line2}
              type="text"
            />

            <FormInput
              required
              placeholder="City"
              name="city"
              handleChange={evt => handleShipping(evt)}
              value={shippingAddress.city}
              type="text"
            />

            <FormInput
              required
              placeholder="State"
              name="state"
              handleChange={evt => handleShipping(evt)}
              value={shippingAddress.state}
              type="text"
            />

            <FormInput
              required
              placeholder="Postal Code"
              name="postal_code"
              handleChange={evt => handleShipping(evt)}
              value={shippingAddress.postal_code}
              type="text"
            />

            <div className="formRow checkoutInput">
              <CountryDropdown
                required
                onChange={val => handleShipping({
                  target: {
                    name: 'country',
                    value: val
                  }
                })}
                value={shippingAddress.country}
                valueType="short"
              />
            </div>

          </div>

          <div className="group">
            <h2>
              Billing Address
            </h2>

            <FormInput
              required
              placeholder="Name on Card"
              name="nameOnCard"
              handleChange={evt => setNameOnCard(evt.target.value)}
              value={nameOnCard}
              type="text"
            />

            <FormInput
              required
              placeholder="Line 1"
              name="line1"
              handleChange={evt => handleBilling(evt)}
              value={billingAddress.line1}
              type="text"
            />

            <FormInput
              placeholder="Line 2"
              name="line2"
              handleChange={evt => handleBilling(evt)}
              value={billingAddress.line2}
              type="text"
            />

            <FormInput
              required
              placeholder="City"
              name="city"
              handleChange={evt => handleBilling(evt)}
              value={billingAddress.city}
              type="text"
            />

            <FormInput
              required
              placeholder="State"
              name="state"
              handleChange={evt => handleBilling(evt)}
              value={billingAddress.state}
              type="text"
            />

            <FormInput
              required
              placeholder="Postal Code"
              name="postal_code"
              handleChange={evt => handleBilling(evt)}
              value={billingAddress.postal_code}
              type="text"
            />

            <div className="formRow checkoutInput">
              <CountryDropdown
                required
                onChange={val => handleBilling({
                  target: {
                    name: 'country',
                    value: val
                  }
                })}
                value={billingAddress.country}
                valueType="short"
              />
            </div>

          </div>

          <div className="group">
            <h2>
              Card Details
            </h2>

            <CardElement
              options={configCardElement}
            />
          </div>

          <Button
            type="submit"
          >
            Pay Now
          </Button>

        </form>
      </div>
    );
  }

  export default PaymentDetails;```
javascript reactjs firebase stripe-payments
3个回答
1
投票

根据文档 https://stripe.com/docs/api/ payment_intents/create 对于 stripe.PaymentIntent.create()

您需要通过此:

import stripe
stripe.api_key = "sk_test_51I5EU6DbwDQYqmKoHRVYU2jw4jtzB8aQa6byuVIMyfDvYl3lxHOzmIRUZ6SabMmk1TV0jNu4w9akIgPY4E3krUbj00ewcroCvC"

  const PaymentIntentVar =  stripe.PaymentIntent.create(
  amount=2000,
  currency="usd",
  payment_method_types=["card"],
)

我猜你有错字吧?付款意向 ? 之后请尝试:

console.log(PaymentIntentVar)

在index.js中 看看您是否得到了正确的回应?请您分享一下好吗!

也在“具有条纹付款的文件”中:

而不是:

const cardElement = elements.getElement('card');

还有这个:

stripe.createPaymentMethod({
          type: 'card',
          card: cardElement,
          billing_details: {
            name: nameOnCard,
            address: {
              ...billingAddress
            }
          }
        })

这样做:

stripe.createPaymentMethod({
          type: 'card',
          card: elements.getElement(CardElement),
          billing_details: {
            name: nameOnCard,
            address: {
              ...billingAddress
            }
          }
        })

还可以通过前端和后端的 console.log() 检查您是否在前端和后端传递了正确的公钥和密钥

也可以使用Stripe,试试这个

import {loadStripe} from '@stripe/stripe-js';

const stripe = loadStripe('secret_key');

0
投票

以下是可能的场景以及我如何理解配置。

  1. 通过
  2. 需要 3D 安全
  3. 失败 - 资金不足

https://stripe.com/docs/ payments/accept-a- payment?platform=web&ui=checkout#additional-testing-resources

首先您尝试从前端付款

      const { error, paymentMethod } = await stripe.createPaymentMethod({
        type: 'card',
        card: cardElement,
        billing_details: {
          name: `${stateProps.userProfile.firstName} ${stateProps.userProfile.lastName}`,
          email: stateProps.user.email
        }
      });

从该 paymentMethod 中,您检索 paymentMethod.Id 并将其发送到您的服务器以进行付款 - 此时我们假设付款将有效并且不需要 3d 安全。

就我而言,我需要的是 paymentMethod.Id,因为我已将所有账单详细信息放在不同的对象中。

在后端,这是我使用 C# 的

    try
    {
        if (request.PaymentMethodId != null)
        {
            var createOptions = new PaymentIntentCreateOptions
            {
                PaymentMethod = request.PaymentMethodId,
                Amount = request.total,
                Currency = "gbp",
                ConfirmationMethod = "manual",
                Confirm = true,
                //ReturnUrl = "",
                Metadata = new Dictionary<string, string>
                {
                    { "OrderId", request.orderId.ToString() },
                }
            };

            paymentIntent = paymentIntentService.Create(createOptions);
        }

        if (request.PaymentIntentId != null)
        {
            var confirmOptions = new PaymentIntentConfirmOptions { };
            paymentIntent = paymentIntentService.Confirm(
                request.PaymentIntentId,
                confirmOptions
            );
        }
    }
    catch (StripeException e)
    {
        return new ViewModels.ResponseObject
        {
            Success = false,
            Title = "An Error Occcured.",
            Message = e.Message,
            Data = e.Message
        };
    }

    if (paymentIntent.Status == "requires_action" && paymentIntent.NextAction.Type == "use_stripe_sdk")
    {
        return new ViewModels.ResponseObject
        {
            Success = false,
            Data = new
            {
                requires_action = true,
                payment_intent_client_secret = paymentIntent.ClientSecret
            },
            Title = "Requires Action",
            Message = "Requires Action"
        };
    }
    else if (paymentIntent.Status == "succeeded")
    {
        return new ViewModels.ResponseObject
        {
            Success = true,
            Title = "Payment Successful.",
            Message = "Thank you. Your payment has been successful. A confirmation message has been sent to you by email.",
            Data = null
        };
    }
    else
    {
        return new ViewModels.ResponseObject
        {
            Success = false,
            Title = "An Error Occcured.",
            Message = "An error has occured with your payment. A representative from our store has been notified and will be in touch with you to resolve the issue.",
            Data = null
        };
    }

因此,如果您阅读代码,您会看到它尝试付款,如果失败,那么它会给您 clientSecret,您可以将其返回给客户端。

您现在可以在前端使用它来构建支付意图(我们已经知道由于 3d secure,该支付意图将失败),该支付意图将自动拉起 3d secure 身份验证窗口。

在我看来,来回两次似乎很浪费,但这就是我设法击败它的方法。


0
投票

当您的元素选项配置不正确时,就会发生这种情况。

我正在使用 vue stripe 框架,当我开发这个框架时,我遇到了同样的错误。

vue 组件设置

<StripeElementPayment
    ref="checkoutRef"
    :pk="stripeConfig._apiKey"
    mode="payment"
    :test-mode="true"
    :elements-options="elementsOptions"
    :confirm-params="confirmParams"
    :locale="stripeConfig._locale"
    :stripe-account="stripeConfig._stripeAccount"
/>

//元素选项,后三个元素不强制测试

elementsOptions: any = {
    appearance: {}, // appearance options
    mode: 'payment',
    currency: 'aud',
    amount: this.totalAmount
}
© www.soinside.com 2019 - 2024. All rights reserved.