简体   繁体   中英

ReactJS Stripe Payments not returning successful message after clicking pay with node and express

I am currently using ReactJS, node, and express with the Stripe Payment API. After clicking the pay button and entering the dummy credit card credentials, the page doesnt process the payment. I have entered the correct publishing key and api key that I got from my dashboard.I believe it likely has somnething to do with what I need to add in the server.js file(aka node backend).I have read through the docs for any clues I can get. Also have searched here on Stack Overflow. None of the questions had the same thing I was looking for. Please see below for pictures and code. Thanks

This is before pressing the button. Please Note the console on the right side. 在此处输入图片说明

This is after pressing the button. The loading spinner just displays forever. Also note the console on right side在此处输入图片说明

    // Donate.js
    import React from "react";
    import "./Donate.css";
    import { loadStripe } from "@stripe/stripe-js";
    import { Elements } from "@stripe/react-stripe-js";
    import CheckoutForm from "./CheckoutForm";
    
    // Make sure to call `loadStripe` outside of a component’s render to avoid
    // recreating the `Stripe` object on every render.
    const stripe = loadStripe(
      "pk*****************************"
    );
    
    stripe.then((data) => {
      console.log(data);
    });
    
    const Donate = () => {
      return (
        <div className="donate">
          <h1 className="donate__sectionHeader">Donate Now</h1>
          <Elements stripe={stripe}>
            <CheckoutForm />
          </Elements>
        </div>
      );
    };
    
    export default Donate;

//CheckoutForm
import React, { useState, useEffect } from "react";
import { CardElement, useStripe, useElements } from "@stripe/react-stripe-js";
import "./CheckoutForm.css";

export default function CheckoutForm() {
  const [succeeded, setSucceeded] = useState(false);
  const [error, setError] = useState(null);
  const [processing, setProcessing] = useState("");
  const [disabled, setDisabled] = useState(true);
  const [clientSecret, setClientSecret] = useState("");
  const stripe = useStripe();
  const elements = useElements();
  useEffect(() => {
    // Create PaymentIntent as soon as the page loads

    window
      .fetch("/donate", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Accept: "application/json",
        },
        body: JSON.stringify({ items: [{ id: "xl-tshirt" }] }),
      })
      .then((res) => {
        return res.json();
      })
      .then((data) => {
        setClientSecret(data.clientSecret);
      });
  }, []);
  const cardStyle = {
    style: {
      base: {
        color: "#32325d",
        fontFamily: "Arial, sans-serif",
        fontSmoothing: "antialiased",
        fontSize: "16px",
        "::placeholder": {
          color: "#32325d",
        },
      },
      invalid: {
        color: "#fa755a",
        iconColor: "#fa755a",
      },
    },
  };
  const handleChange = async (event) => {
    // Listen for changes in the CardElement
    // and display any errors as the customer types their card details
    setDisabled(event.empty);
    setError(event.error ? event.error.message : "");
  };
  const handleSubmit = async (ev) => {
    ev.preventDefault();
    setProcessing(true);
    const payload = await stripe.confirmCardPayment(clientSecret, {
      payment_method: {
        card: elements.getElement(CardElement),
      },
    });
    if (payload.error) {
      setError(`Payment failed ${payload.error.message}`);
      setProcessing(false);
    } else {
      setError(null);
      setProcessing(false);
      setSucceeded(true);
    }

    console.log(clientSecret);
  };
  return (
    <form id="payment-form" onSubmit={handleSubmit}>
      <CardElement
        id="card-element"
        options={{ hidePostalCode: true, cardStyle }}
        onChange={handleChange}
      />
      <button disabled={processing || disabled || succeeded} id="submit">
        <span id="button-text">
          {processing ? <div className="spinner" id="spinner"></div> : "Pay"}
        </span>
      </button>
      {/* Show any error that happens when processing the payment */}
      {error && (
        <div className="card-error" role="alert">
          {error}
        </div>
      )}
      {/* Show a success message upon completion */}
      <p className={succeeded ? "result-message" : "result-message hidden"}>
        Payment succeeded, see the result in your
        <a href={`https://dashboard.stripe.com/test/payments`}>
          {" "}
          Stripe dashboard.
        </a>{" "}
        Refresh the page to pay again.
      </p>
    </form>
  );
}


//server.js
const express = require("express");
const app = express();
const { resolve } = require("path");
// This is your real test secret API key.
const stripe = require("stripe")(
  "sk_test_**********************************"
);
app.use(express.static("."));
app.use(express.json());

const calculateOrderAmount = (items) => {
  // Replace this constant with a calculation of the order's amount
  // Calculate the order total on the server to prevent
  // people from directly manipulating the amount on the client
  return 1400;
};

app.post("/create-payment-intent", async (req, res) => {
  const { items } = req.body;

  // Create a PaymentIntent with the order amount and currency
  const paymentIntent = await stripe.paymentIntents.create({
    amount: 1099,
    currency: "usd",
    // Verify your integration in this guide by including this parameter
    metadata: { integration_check: "accept_a_payment" },
  });
  res.send({
    clientSecret: paymentIntent.client_secret,
  });
});

app.listen(4242, () => console.log("Node server listening on port 4242!"));

You need to review the server call/network response with the client_secret . The console error indicates you've provided an invalid secret to confirmCardPayment , apparently an empty string.

You specified: .

It would appear that your app is not setting the state via setClientSecret as intended, and you end up with the initial empty string value from useState(""); .

Check your client_secret value before the confirmCardPayment call, and step backwards to find where the value is being dropped.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM