未捕获(承诺中)IntegrationError:Stripe() 缺少值:apiKey 应该是字符串。仅在部署到 vercel 时但在本地工作正常

Jay*_*Kay 2 stripe-payments reactjs react-redux next.js vercel

我的本地主机上的条带结帐会话工作正常,但是当我尝试从部署的网站的结帐页面重定向时,出现错误。

在此输入图像描述

我认为错误来自的代码:

/src/pages/checkout.js

import { useSession } from "next-auth/client";
import Image from "next/image";
import { useSelector } from "react-redux";
import CheckoutProduct from "../components/CheckoutProduct";
import Header from "../components/Header";
import Currency from "react-currency-formatter";
import { selectItems, selectTotal } from "../slices/basketSlice";
import { loadStripe } from "@stripe/stripe-js";
import axios from "axios";

const stripePromise = loadStripe(process.env.stripe_public_key);

function checkout() {
  const items = useSelector(selectItems);
  const total = useSelector(selectTotal);
  const [session] = useSession();

  const createCheckoutSession = async () => {
    const stripe = await stripePromise;

    // call the backend to create a checkout session
    const checkoutSession = await axios.post("/api/create-checkout-session", {
      items: items,
      email: session.user.email,
    });
    // redirect customers to stripe checkout
    const result = await stripe.redirectToCheckout({
      sessionId: checkoutSession.data.id,
    });
    if (result.error) {
      alert(result.error.message);
    }
  };

  return (
    <div className="h-screen">
      <Header />
      <main className="lg:flex flex-1 overflow-y-auto max-w-screen-2xl mx-auto">
        {/* Left side */}
        <div className="flex-grow m-5 shadow-sm">
          <Image
            src="/images/amazon-cart.jpg"
            width={1020}
            height={250}
            objectFit="contain"
          />
          <div className="fex flex-col p-5 space-y-10 bg-white">
            <h1 className="text-3xl border-b pb-4">
              {items.length === 0
                ? "Your Amazon basket is empty"
                : "Shopping Basket"}
            </h1>
            {items.map((item, i) => (
              <CheckoutProduct
                key={i}
                id={item.id}
                title={item.title}
                rating={item.rating}
                price={item.price}
                description={item.description}
                category={item.category}
                image={item.image}
                hasPrime={item.hasPrime}
              />
            ))}
          </div>
        </div>

        {/* Right side */}
        <div className="flex flex-col bg-white p-10 shadow-md">
          {items.length > 0 && (
            <>
              <h2 className="whitespace-nowrap">
                Subtotal ({items.length} items):
                <span className="font-bold">
                  <Currency quantity={total} currency="EUR" />
                </span>
              </h2>
              <button
                role="link"
                onClick={createCheckoutSession}
                disabled={!session}
                className={`button mt-2 ${
                  !session &&
                  "from-gray-300 to-gray-500 border-gray-200 text-gray-300 cursor-not-allowed"
                }`}
              >
                {!session ? "Sign in to Checkout" : "Proceed to Checkout"}
              </button>
            </>
          )}
        </div>
      </main>
    </div>
  );
}

export default checkout;
Run Code Online (Sandbox Code Playgroud)

/next.config.js

module.exports = {

  env: {
    stripe_public_key: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY,
  },
};
Run Code Online (Sandbox Code Playgroud)

我的环境变量也部署在 Vercel 上,命名约定如下:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_mykey

# Stripe Terminal/CLI
STRIPE_WEBHOOK_SECRET=whsec_mywebhooksecret

STRIPE_SECRET_KEY=sk_test_mysecret
Run Code Online (Sandbox Code Playgroud)

/src/pages/api/create-checkout-session.js

const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

export default async (req, res) => {
  const { items, email } = req.body;
  //   console.log(items);
  //   console.log(email);
  const transformedItems = items.map((item) => ({
    price_data: {
      currency: "eur",
      product_data: {
        name: item.title,
        images: [item.image],
      },
      unit_amount: item.price * 100,
    },
    description: item.description,
    quantity: 1,
  }));

  const session = await stripe.checkout.sessions.create({
    payment_method_types: ["card"],
    shipping_rates: ["shr_1JPZN2HHQ2qhqkUCKLyMJDLO"],
    shipping_address_collection: {
      allowed_countries: ["GB", "US", "CA", "DE"],
    },
    line_items: transformedItems,
    mode: "payment",
    success_url: `${process.env.HOST}/success`,
    cancel_url: `${process.env.HOST}/checkout`,
    metadata: {
      email,
      images: JSON.stringify(items.map((item) => item.image)),
    },
  });

  res.status(200).json({ id: session.id });
};
Run Code Online (Sandbox Code Playgroud)

/src/pages/api/webhook.js

import { buffer } from "micro";
import * as admin from "firebase-admin";

// secure a connection to FIREBASE from backend
const serviceAccount = require("../../../permissions.json");

const app = !admin.apps.length
  ? admin.initializeApp({
      credential: admin.credential.cert(serviceAccount),
    })
  : admin.app();

//   Establish connection to stripe
const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY);

const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET;

const fullfillOrder = async (session) => {
  //console.log("Fulfilling order", session);

  return app
    .firestore()
    .collection("users")
    .doc(session.metadata.email)
    .collection("orders")
    .doc(session.id)
    .set({
      amount: session.amount_total / 100,
      amount_shipping: session.total_details.amount_shipping / 100,
      images: JSON.parse(session.metadata.images),
      timestamp: admin.firestore.FieldValue.serverTimestamp(),
      customer_email: session.customer_details.email,
    })
    .then(() => {
      console.log(`SUCCESS: Order ${session.id} has been added to DB`);
    });
};

export default async (req, res) => {
  if (req.method === "POST") {
    const requestBuffer = await buffer(req);
    const payload = requestBuffer.toString();
    const sig = req.headers["stripe-signature"];
    let event;
    //   verify that the event posted came from stripe
    try {
      event = stripe.webhooks.constructEvent(payload, sig, endpointSecret);
    } catch (error) {
      console.log("ERROR while constructing event", error.message);
      return res
        .status(400)
        .send(`Webhook error while constructing event:${error.message}`);
    }

    // Handle checkout.session.completed event
    if (event.type === "checkout.session.completed") {
      const session = event.data.object;

      //   fulfill the order...
      return fullfillOrder(session)
        .then(() => res.status(200))
        .catch((err) => {
          console.log("ERROR while fulfilling order", err.message);
          res
            .status(400)
            .send(`Webhook Error while fulfilling order: ${err.message}`);
        });
    }
  }
};

export const config = {
  api: {
    bodyParser: false,
    externalResolver: true,
  },
};
Run Code Online (Sandbox Code Playgroud)

该应用程序托管在 Vercel 上。使用 Next.js / React / Redux 创建。连接到 Firebase / Stripe,我使用 Axios。

这段代码是错误的根源吗?理解此错误最困难的部分是我的应用程序在本地主机中运行得很好,控制台中所有页面上的问题为零,但在部署的网站上出现了此错误。

我的代码的哪一部分可能是错误的?我希望能够单击该按钮并进入 Stripe 结账页面。

小智 8

代替 ...

const stripePromise = loadStripe(process.env.stripe_public_key);

和 ...

const stripePromise = loadStripe(`${process.env.stripe_public_key}');

...希望对您有帮助。