Next.js 14:在 getServerSideProps 中序列化产品时出现未定义值错误

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

我正在使用 Next.js 14.2.3 并尝试使用 getServerSideProps 中 @stripe/firestore-stripe- payment 中的 getProducts 函数从 Firestore 获取产品列表。但是,我遇到了序列化错误:

服务器错误
错误:序列化从“/”中的

.products
返回的
getServerSideProps
时出错。
原因:
undefined
无法序列化为JSON。请使用
null
或省略此值。

这是我的代码的相关部分:

import Head from "next/head";
import Header from "@/components/Header";
import Banner from "@/components/Banner";
import { Movie } from "@/typings";
import requests from "@/utils/requests";
import Row from "@/components/Row";
import useAuth from "@/hooks/useAuth";
import { useRecoilValue } from "recoil";
import { modalState } from "@/atoms/moduleAtom";
import Modal from "@/components/Modal";
import Plans from "@/components/Plans";
import { Product, getProducts } from "@stripe/firestore-stripe-payments";
import payments from "@/lib/stripe";

interface Props {
netflixOriginals: Movie[];
trendingNow: Movie[];
topRated: Movie[];
actionMovies: Movie[];
comedyMovies: Movie[];
horrorMovies: Movie[];
romanceMovies: Movie[];
documentaries: Movie[]
products: Product[]
}

const Home = ({
netflixOriginals,
actionMovies,
comedyMovies,
documentaries,
horrorMovies,
romanceMovies,
topRated,
trendingNow,
products
Props) => {
console.log(products)
const { logout, loading } = useAuth()
const showModal = useRecoilValue(modalState)
const subscription = false


if (loading || subscription === null) return 
null

if (!subscription) return <Plans/>


return (
    <div
this is so we cant scroll when we open the modal
className={`relative h-screen bg-gradient-to-b lg:h-[140vh] ${showModal && "!h-screen overflow-hidden"}`}
    >
      <Head>
        <title>Home - Netflix</title>
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <Header />
      <main className="relative pl-4 pb-24 lg:space-y24 lg:pl-16">
        <Banner netflixOriginals={netflixOriginals}/>
        <section className="md:space-y-24">
        <Row title="Trending Now" movies={trendingNow} />
          <Row title="Top Rated" movies={topRated} />
          <Row title="Action Thrillers" movies={actionMovies} />
My List Component*/}
          <Row title="Comedies" movies={comedyMovies} />
          <Row title="Scary Movies" movies={horrorMovies} />
          <Row title="Romance Movies" movies={romanceMovies} />
          <Row title="Documentaries" movies={documentaries} />
        </section>
      </main> 
     {showModal} && <Modal />
    </div>
  );

}

export const getServerSideProps = async () => {
const products = await getProducts(payments, {
includePrices: true,
activeOnly: true
  }).then((res) => res).catch((error) => console.log(error.message))

const [
netflixOriginals,
trendingNow,
topRated,
actionMovies,
comedyMovies,
horrorMovies,
romanceMovies,
documentaries,
await Promise.all([
fetch(requests.fetchNetflixOriginals).then((res) => res.json()),
fetch(requests.fetchTrending).then((res) => res.json()),
fetch(requests.fetchTopRated).then((res) => res.json()),
fetch(requests.fetchActionMovies).then((res) => res.json()),
fetch(requests.fetchComedyMovies).then((res) => res.json()),
fetch(requests.fetchHorrorMovies).then((res) => res.json()),
fetch(requests.fetchRomanceMovies).then((res) => res.json()),
fetch(requests.fetchDocumentaries).then((res) => res.json()),
  ]);
return {
props: {
netflixOriginals: netflixOriginals.results,
trendingNow: trendingNow.results,
topRated: topRated.results,
actionMovies: actionMovies.results,
comedyMovies: comedyMovies.results,
horrorMovies: horrorMovies.results,
romanceMovies: romanceMovies.results,
documentaries: documentaries.results,
products
    },
  };
};

export default Home;

我尝试过的:

  • 我为 getProducts 调用添加了错误处理,以确保它记录任何问题。
  • 我尝试使用 JSON.stringify 和 JSON.parse 将未定义的值转换为 null 来清理产品数组。
  • 我多次重新启动 Firebase、创建新数据库并设置新的 Stripe 产品。
  • 我验证了我的 Firebase 数据库中存在该产品集合。
  • 我确认 Firebase 已正确附加到我的应用程序,因为新用户在注册后已成功添加到 Firebase 数据库中。 尽管做出了这些努力,序列化错误仍然存在,这表明产品数组中可能仍然存在未定义的值。

我希望

getServerSideProps
函数能够在不遇到序列化问题的情况下获取产品和其他电影数据,从而允许将产品数组传递到组件而不会出现任何错误。

javascript firebase next.js stripe-payments
1个回答
0
投票

大家好

对于遇到类似问题的人来说,问题似乎是 源于使用过时版本的 Stripe SDK。解决 为此,我建议直接实现 Stripe API,而不是 依赖过时的 SDK。

以下是您可以采取的方法的概述:

获取产品和价格:如果您仍然需要获取产品和价格 来自 Firestore 的价格数据,创建 fetchProducts.ts 文件以 动态检索此信息。这是获取代码 产品:

// fetchProducts.ts

    import { db } from '../firebase';
    import { collection, query, where, getDocs } from 'firebase/firestore';
    
    const fetchProducts = async (): Promise<any[]> => {
      const products: any[] = [];
    
      try {
        const productsCollection = collection(db, 'products');
        const q = query(productsCollection, where('active', '==', true));
        const querySnapshot = await getDocs(q);
    
        for (const doc of querySnapshot.docs) {
          const productData = doc.data();
          const pricesCollection = collection(doc.ref, 'prices');
          const priceSnap = await getDocs(pricesCollection);
    
          const prices = priceSnap.docs.map((priceDoc) => ({
            id: priceDoc.id,
            ...priceDoc.data(),
          }));
    
          products.push({
            id: doc.id,
            ...productData,
            prices,
          });
        }
      } catch (error) {
        console.error('Error fetching products:', error);
      }
    
      return products;
    };
    
    export default fetchProducts;

使用 Stripe Checkout 开始订阅:使用以下代码 通过在中创建新文档来启动订阅的代码片段 用户的 checkout_sessions 集合。 Firestore 扩展 将使用 Stripe Checkout 会话 ID 更新此文档,您可以使用该 ID 可用于将用户重定向到结帐页面。

import { collection, addDoc, doc, onSnapshot } from 'firebase/firestore';
import { auth, db } from '../firebase';

const createCheckoutSession = async (priceId: string) => {
  const user = auth.currentUser;
  if (!user) throw new Error('No authenticated user found.');

  const uid = user.uid;

  // Create a checkout session in Firestore
  const col = collection(db, 'customers', uid, 'checkout_sessions');
  const docRef = await addDoc(col, {
    price: priceId,
    success_url: window.location.origin,
    cancel_url: window.location.origin,
  });

  

// 监听要创建的结帐会话并获取 URL

return new Promise<string>((resolve, reject) => {
    const unsub = onSnapshot(doc(db, 'customers', uid, 'checkout_sessions', docRef.id), (snap) => {
      const data = snap.data();
      if (data?.url) {
        unsub();
        resolve(data.url);
      } else if (data?.error) {
        unsub();
        reject(new Error(`An error occurred: ${data.error.message}`));
      }
    });
  });
};

export default createCheckoutSession;

集成到您的组件中:使用 createCheckoutSession 函数 在您的组件中处理订阅过程。这是一个 如何集成它的示例:

import createCheckoutSession from './path/to/your/createCheckoutSession';

const subscribeToPlan = async (priceId: string) => {
  try {
    const url = await createCheckoutSession(priceId);
    window.location.assign(url);
  } catch (error) {
    console.error('Error creating checkout session:', error);
  }
};

另外,你可以参考这个视频

https://youtu.be/xi3F2Zv91UE?t=1311

查看如何设置 Stripe Checkout Firestore。

我希望这有助于解决您面临的问题!

© www.soinside.com 2019 - 2024. All rights reserved.