0

0

Next.js 13 应用路由中 Stripe 数据获取的深度解析与实践

聖光之護

聖光之護

发布时间:2025-11-21 12:39:32

|

817人浏览过

|

来源于php中文网

原创

next.js 13 应用路由中 stripe 数据获取的深度解析与实践

在 Next.js 13 App Router 环境下,传统的数据获取方法如 `getStaticProps` 已被废弃,导致在客户端组件中直接调用 Stripe API 时常出现 `undefined` 错误。本文将深入探讨 Next.js 13 的新数据获取范式,区分服务器组件与客户端组件的数据处理策略,并提供在服务器组件中安全获取 Stripe 数据的方法,以及在客户端组件中利用自定义缓存策略优化数据获取的实践方案,旨在帮助开发者规避常见陷阱,构建高效稳定的应用。

引言:Next.js 13 应用路由与数据获取的挑战

随着 Next.js 13 App Router 的引入,数据获取和组件渲染的范式发生了根本性转变。开发者在尝试将旧有的 Pages Router 模式(如 getStaticProps)迁移到新的 App Router 架构时,经常会遇到数据获取失败,尤其是在客户端组件中直接与第三方服务(如 Stripe)交互时,数据返回 undefined 的问题。这主要是因为 getStaticProps 等数据获取方法在 App Router 中已被废弃,且客户端组件与服务器组件在数据获取能力和安全边界上存在显著差异。理解这些变化是成功构建 Next.js 13 应用的关键。

理解 Next.js 13 App Router 的数据获取范式

Next.js 13 App Router 引入了服务器组件(Server Components)和客户端组件(Client Components)的概念,这彻底改变了数据获取的最佳实践。

  1. 服务器组件 (Server Components):

    • 默认情况下,App Router 中的所有组件都是服务器组件。
    • 它们在服务器上渲染,可以安全地访问后端资源、数据库和敏感的 API 密钥(如 Stripe Secret Key)。
    • 数据获取可以直接在服务器组件中进行,可以使用 async/await 结合 fetch API 或直接调用后端 SDK。
    • 服务器组件不具备交互性(如 useState, useEffect)。
  2. 客户端组件 (Client Components):

    • 通过在文件顶部添加 'use client' 指令来声明。
    • 浏览器上渲染,具备交互性,可以响应用户事件。
    • 不应直接访问敏感的 API 密钥,因为这些密钥会暴露在客户端代码中。
    • 数据获取通常通过 API 路由(Server Actions)或第三方库(如 SWR, React Query)进行,或者通过从服务器组件传递 props 获取。

在服务器组件中安全地获取 Stripe 数据

鉴于 Stripe Secret Key 的敏感性,最佳实践是在服务器组件中进行 Stripe API 调用。这样可以确保密钥永远不会暴露在客户端浏览器中。

1. 环境配置

确保你的 .env.local 文件正确配置了 Stripe 密钥:

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY = pk_test_apikeycontinues
STRIPE_SECRET_KEY = sk_test_apikeycontinues

STRIPE_SECRET_KEY 是私有密钥,只能在服务器端使用。NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY 是公共密钥,可以在客户端使用。

2. Stripe 实例初始化

你的 utils/stripe.js 文件应该只在服务器端组件中被导入和使用,以避免将 STRIPE_SECRET_KEY 暴露给客户端。

// ./app/utils/stripe.js
import Stripe from 'stripe';

// 确保在服务器端执行,否则 process.env.STRIPE_SECRET_KEY 将是 undefined
// 如果此文件被客户端组件导入,Stripe 实例将无法正确初始化
export const stripe = new Stripe(process.env.STRIPE_SECRET_KEY, {
  apiVersion: '2023-10-16', // 建议指定API版本
});

3. 服务器组件示例:获取产品列表

在一个服务器组件中,你可以直接导入 stripe 实例并调用其方法。

// ./app/page.js (这是一个服务器组件,因为没有 'use client' 指令)
import { stripe } from "./utils/stripe"; // 确保此导入仅在服务器端使用
import ProductCard from './components/ProductCard'; // 假设 ProductCard 是一个客户端组件

export default async function HomePage() {
  const inventory = await stripe.products.list({
    limit: 5,
  });

  const products = inventory.data; // 获取实际的产品数据

  return (
    

我们的产品

{products.map((product) => ( // 如果 ProductCard 是客户端组件,数据作为 props 传递 ))}
); } // components/ProductCard.js (如果需要交互性,则为客户端组件) // 'use client'; // import React from 'react'; // export default function ProductCard({ product }) { // return ( //
//

{product.name}

//

{product.description}

Action Figure AI
Action Figure AI

借助Action Figure AI的先进技术,瞬间将照片转化为定制动作人偶。

下载
// {/* ... 更多产品详情和交互按钮 */} //
// ); // }

在这个例子中,HomePage 是一个服务器组件,它负责安全地从 Stripe 获取数据,然后可以将这些数据作为 props 传递给任何客户端组件进行渲染和交互。

客户端组件中的数据获取策略

尽管服务器组件是获取敏感数据的首选,但在某些场景下,客户端组件可能需要独立获取数据(例如,用户交互触发的动态数据加载)。然而,直接在客户端组件中使用 fetch 结合 use Hook 可能会导致重复渲染问题,且不应直接暴露敏感密钥。

1. 直接 fetch 的限制与挑战

Next.js 13 引入了 use Hook 来在客户端组件中读取 Promise。然而,如果处理不当,每次组件渲染时都可能触发新的 fetch 请求,导致性能问题。

2. 推荐方案:第三方数据获取库

对于客户端组件中的复杂数据获取和状态管理,推荐使用成熟的第三方库,如 SWRReact Query。它们提供了缓存、去重、错误处理、重新验证等高级功能,能有效提升开发体验和应用性能。

3. 优化 use Hook 的自定义策略(避免重复渲染)

为了解决在客户端组件中使用 use Hook 导致重复 fetch 的问题,可以实现一个简单的缓存机制来存储 Promise,确保同一请求只执行一次。

// utils/queryClient.ts (可以在任何地方定义,但通常放在 utils 文件夹)
// 这是一个通用的 Promise 缓存函数,用于防止重复的数据请求
const fetchMap = new Map>();

function queryClient(
  name: string,
  query: () => Promise
): Promise {
  if (!fetchMap.has(name)) {
    fetchMap.set(name, query());
  }
  return fetchMap.get(name)!;
}

export { queryClient };

4. 在客户端组件中使用 queryClient

当客户端组件需要获取数据时,它应该通过一个安全的 API 路由来代理对 Stripe 的请求,而不是直接调用 Stripe API。这里假设你有一个 Next.js API 路由 (/api/products) 来处理 Stripe 请求。

// ./app/home-client.js (一个客户端组件)
'use client'

import { use } from 'react';
import { queryClient } from './utils/queryClient'; // 导入自定义的 queryClient

// 假设你有一个 Next.js API 路由来处理 Stripe 请求,例如 /api/products
// 这个 API 路由会在服务器端使用 STRIPE_SECRET_KEY 调用 Stripe API
async function fetchProductsFromApi() {
  const response = await fetch('/api/products', {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
    },
    // body: JSON.stringify({ slug }), // 如果需要传递参数
  });
  if (!response.ok) {
    throw new Error('Failed to fetch products');
  }
  return response.json();
}

export default function HomeClient() {
  // 使用 queryClient 缓存 fetchProductsFromApi 的 Promise
  // "stripe-products-list" 是一个唯一的键,用于缓存此特定请求
  const { products } = use(
    queryClient("stripe-products-list", fetchProductsFromApi)
  );

  console.log("Products in client component:", products);

  if (!products) {
    return 
加载中...
; } return (

客户端组件中的产品列表

    {products.data.map((product) => ( // 假设 products 结构与 Stripe API 返回的 inventory 类似
  • {product.name}
  • ))}
); } // 示例:/app/api/products/route.js (一个服务器端 API 路由) // import { stripe } from '../../../utils/stripe'; // 确保路径正确 // export async function GET(request) { // try { // const inventory = await stripe.products.list({ limit: 5 }); // return new Response(JSON.stringify({ products: inventory }), { // status: 200, // headers: { 'Content-Type': 'application/json' }, // }); // } catch (error) { // console.error('Error fetching products:', error); // return new Response(JSON.stringify({ error: 'Failed to fetch products' }), { // status: 500, // headers: { 'Content-Type': 'application/json' }, // }); // } // }

注意事项:

  • 客户端组件绝不能直接导入包含 STRIPE_SECRET_KEY 的 utils/stripe.js 文件。
  • 客户端组件应通过调用 Next.js API 路由(Server Actions 也是一个很好的选择)来间接访问敏感的 Stripe API。API 路由会在服务器端执行,安全地处理敏感密钥。
  • 上述 queryClient 模式是一种简单的缓存策略,对于更复杂的需求,仍然推荐使用 SWR 或 React Query。

总结与最佳实践

在 Next.js 13 App Router 中集成 Stripe 时,遵循以下最佳实践至关重要:

  1. 优先使用服务器组件获取数据: 尽可能在服务器组件中进行数据获取,特别是涉及敏感 API 密钥的请求(如 Stripe Secret Key)。这不仅保证了安全性,还能利用服务器端渲染的优势。
  2. 区分服务器组件和客户端组件: 明确组件的职责。服务器组件负责数据获取和初始渲染,客户端组件负责交互性和动态内容。
  3. 安全处理环境变量 STRIPE_SECRET_KEY 必须仅在服务器端使用。NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY 可以在客户端安全使用。
  4. 客户端组件的数据获取策略:
    • 通过 Next.js API 路由或 Server Actions 代理对敏感 API 的请求。
    • 对于客户端组件内部需要获取的数据,考虑使用第三方数据获取库(SWR, React Query)来管理状态、缓存和重新验证。
    • 如果选择使用 use Hook 结合 fetch,务必实现适当的缓存机制(如本文的 queryClient)来避免不必要的重复请求。
  5. 查阅官方文档: Next.js 13 仍在快速发展中,始终参考最新的官方文档,尤其是数据获取和 App Router 迁移指南,以获取最准确和最新的信息。

通过采纳这些策略,开发者可以有效地在 Next.js 13 App Router 环境中集成 Stripe,构建安全、高效且可维护的现代 Web 应用程序。

相关文章

路由优化大师
路由优化大师

路由优化大师是一款及简单的路由器设置管理软件,其主要功能是一键设置优化路由、屏广告、防蹭网、路由器全面检测及高级设置等,有需要的小伙伴快来保存下载体验吧!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
js正则表达式
js正则表达式

php中文网为大家提供各种js正则表达式语法大全以及各种js正则表达式使用的方法,还有更多js正则表达式的相关文章、相关下载、相关课程,供大家免费下载体验。

510

2023.06.20

js获取当前时间
js获取当前时间

JS全称JavaScript,是一种具有函数优先的轻量级,解释型或即时编译型的编程语言;它是一种属于网络的高级脚本语言,主要用于Web,常用来为网页添加各式各样的动态功能。js怎么获取当前时间呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

244

2023.07.28

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

254

2023.08.03

js是什么意思
js是什么意思

JS是JavaScript的缩写,它是一种广泛应用于网页开发的脚本语言。JavaScript是一种解释性的、基于对象和事件驱动的编程语言,通常用于为网页增加交互性和动态性。它可以在网页上实现复杂的功能和效果,如表单验证、页面元素操作、动画效果、数据交互等。

5270

2023.08.17

js删除节点的方法
js删除节点的方法

js删除节点的方法有:1、removeChild()方法,用于从父节点中移除指定的子节点,它需要两个参数,第一个参数是要删除的子节点,第二个参数是父节点;2、parentNode.removeChild()方法,可以直接通过父节点调用来删除子节点;3、remove()方法,可以直接删除节点,而无需指定父节点;4、innerHTML属性,用于删除节点的内容。

477

2023.09.01

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

206

2023.09.04

Js中concat和push的区别
Js中concat和push的区别

Js中concat和push的区别:1、concat用于将两个或多个数组合并成一个新数组,并返回这个新数组,而push用于向数组的末尾添加一个或多个元素,并返回修改后的数组的新长度;2、concat不会修改原始数组,是创建新的数组,而push会修改原数组,将新元素添加到原数组的末尾等等。本专题为大家提供concat和push相关的文章、下载、课程内容,供大家免费下载体验。

217

2023.09.14

js截取字符串的方法介绍
js截取字符串的方法介绍

JavaScript字符串截取方法,包括substring、slice、substr、charAt和split方法。这些方法可以根据具体需求,灵活地截取字符串的不同部分。在实际开发中,根据具体情况选择合适的方法进行字符串截取,能够提高代码的效率和可读性 。

218

2023.09.21

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

3

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 3.6万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号