简体   繁体   English

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

[英]Uncaught (in promise) IntegrationError: Invalid value for stripe.confirmCardPayment intent secret

I get this error when trying to checkout with stripe:尝试使用条纹结帐时出现此错误:

Uncaught (in promise) IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client secret of the form ${id} secret ${secret}.未捕获(承诺中)IntegrationError:stripe.confirmCardPayment 意图秘密的值无效:值应该是形式为 ${id}秘密${secret} 的客户端秘密。 You specified: .....您指定:......

I use stripe on my website and I've implemented it with firebase functions.我在我的网站上使用了条带,并使用 firebase 函数实现了它。 When I run my website and firebase functions locally I do not get this error, but when I have it on my firebase hosting it does not work and I get that error.当我在本地运行我的网站和 firebase 功能时,我没有收到此错误,但是当我在我的 firebase 主机上安装它时,它不起作用,我收到了该错误。 Locally I would run these commands: npm start to start the website and then I cd inside the functions folder and then run npm run serve .在本地我会运行这些命令: npm start启动网站,然后我在函数文件夹中 cd 然后运行npm run serve How can I fix this?我怎样才能解决这个问题? Here is the index.js file that is being run with firebase functions: index.js这是使用 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);

Here's the package.json这是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"
  ]
 }
}

File that has stripe payment具有条带付款的文件

  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;```

According to the documentation https://stripe.com/docs/api/payment_intents/create for stripe.PaymentIntent.create()根据文档https://stripe.com/docs/api/payment_intents/create for stripe.PaymentIntent.create()

You need to pass this:你需要通过这个:

import stripe
stripe.api_key = "sk_test_51I5EU6DbwDQYqmKoHRVYU2jw4jtzB8aQa6byuVIMyfDvYl3lxHOzmIRUZ6SabMmk1TV0jNu4w9akIgPY4E3krUbj00ewcroCvC"

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

You have a typo, I guess?你有错字,我猜? PaymentIntents?付款意图? After please try to:之后请尝试:

console.log(PaymentIntentVar)

in index.js To see if you are getting the correct response?在 index.js 中查看是否得到了正确的响应? Would you please share that !你能分享一下吗!

Also in " File that has stripe payment":同样在“具有条带付款的文件”中:

instead of:代替:

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

and this:和这个:

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

do this:做这个:

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

also check you are passing the correct public and secret keys on your front and backend by console.log() on front and backend还要通过前端和后端的 console.log() 检查您是否在前端和后端传递了正确的公钥和密钥

Also instead useStripe, try this也改为使用Stripe,试试这个

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

const stripe = loadStripe('secret_key');

Here are the possible scenarios and how I understand the configuration.以下是可能的情况以及我如何理解配置。

  1. pass经过
  2. requires 3d secure需要 3d 安全
  3. fail - insufficient funds失败 - 资金不足

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

So first you attempt a payment from the front end所以首先你尝试从前端付款

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

from that paymentMethod, you retrieve paymentMethod.Id and send that to your server to make a payment - at this point we are assuming the payment will work and not require 3d secure.从该 paymentMethod 中,您检索 paymentMethod.Id 并将其发送到您的服务器以进行付款 - 此时我们假设付款将起作用并且不需要 3d 安全。

In my case, I need is that paymentMethod.Id because I have put all the billing details in a different object.就我而言,我需要的是 paymentMethod.Id,因为我已将所有账单明细放在不同的 object 中。

In the backend, here is what I have using C#在后端,这是我使用 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
        };
    }

So if you read the code, you will see that it tries to make a payment and if that fails, THEN it gives you the clientSecret and you can return that to the client.因此,如果您阅读代码,您会看到它尝试付款,如果失败,那么它会为您提供 clientSecret,您可以将其返回给客户端。

This is what you can now use on the front end to construct a payment intent (which we already know will fail due to 3d secure) that will automatically pull up the 3d secure authentication window.这就是您现在可以在前端使用来构建支付意图(我们已经知道由于 3d 安全而失败),它将自动拉起 3d 安全身份验证 Z05B8C74CBD96FBF2DE4C1A352702FFF4Z。

In my opinion it seems a waste to do the roundtrip twice but that's how I managed to beat it into submission.在我看来,往返两次似乎是一种浪费,但这就是我设法击败它的方式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 获取 IntegrationError:stripe.confirmCardPayment 意图密码的值无效:值应该是 client_secret 字符串 - Getting IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client_secret string 我收到 IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client_secret string - I am getting IntegrationError: Invalid value for stripe.confirmCardPayment intent secret: value should be a client_secret string stripe.confirmCardPayment 意图秘密返回空字符串 - stripe.confirmCardPayment intent secret Returns Empty String NEXJS stripe v3:1 Uncaught (in promise) IntegrationError: Missing value for Stripe(): apiKey should be a string - NEXJS stripe v3:1 Uncaught (in promise) IntegrationError: Missing value for Stripe(): apiKey should be a string 未处理 Promise 拒绝:IntegrationError:stripe.confirmPayment() 的无效值:元素应该有一个已安装的支付元素 - Unhandled Promise Rejection: IntegrationError: Invalid value for stripe.confirmPayment(): elements should have a mounted Payment Element IntegrationError:stripe.confirmPayment() 的无效值:React Stripe 中出现错误 - IntegrationError: Invalid value for stripe.confirmPayment(): Getting error in React Stripe 我应该如何将`cardNumberElement`、`cardExpiryElement`和`cardCvcElement`传递到`stripe.confirmCardPayment`的`payment_method.card`? - How should I pass `cardNumberElement`, `cardExpiryElement` and `cardCvcElement` into `stripe.confirmCardPayment`'s `payment_method.card`? 未处理的拒绝(TypeError):无法读取 React.js 中 stripe.confirmCardPayment 中未定义的属性“id” - Unhandled Rejection (TypeError): Cannot read property 'id' of undefined in stripe.confirmCardPayment in React.js 我正在尝试通过 Stripe.js 库获取卡片令牌,但得到 Uncaught IntegrationError - I'm trying to grab a card token through Stripe.js library but get Uncaught IntegrationError 未捕获(承诺)错误:提供给 `Elements` 的道具 `stripe` 无效。 我们建议使用来自 `@stripe/stripe-js` 的 `loadStripe` 实用程序 - Uncaught (in promise) Error: Invalid prop `stripe` supplied to `Elements`. We recommend using the `loadStripe` utility from `@stripe/stripe-js`
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM