如何在客户端组件中获取数据且不暴露API Key并实现分页
解决方案:通过内部API代理+客户端状态管理实现安全分页
核心思路是用Next.js API路由作为中间代理层,让服务器端替客户端调用外部API(API_KEY仅在服务器端使用,不会暴露给客户端),客户端通过调用这个内部路由获取数据,同时在客户端组件里管理分页状态。
步骤1:创建内部API代理路由
在app/api/data/route.ts创建API路由,负责转发请求到外部API并携带密钥:
// app/api/data/route.ts import { NextResponse } from 'next/server'; export async function GET(request: Request) { const { searchParams } = new URL(request.url); const page = searchParams.get('page') || '1'; // 服务器端调用外部API,安全使用环境变量中的API_KEY const response = await fetch(`https://api/data?key=${process.env.API_KEY}&page=${page}`); if (!response.ok) { return NextResponse.json({ error: '数据获取失败' }, { status: response.status }); } const data = await response.json(); return NextResponse.json(data.results); }
步骤2:修改客户端组件的分页逻辑
在客户端组件中管理页码状态,通过内部API路由获取对应页的数据:
// ClientComponent.tsx 'use client'; import { useState, useEffect } from 'react'; import { Pagination } from '@mui/material'; import { Card } from '../page'; import Cards from './Cards'; export default function ClientComponent({ initialData }: { initialData: Card[] }) { const [data, setData] = useState<Card[]>(initialData); const [currentPage, setCurrentPage] = useState(1); const [isLoading, setIsLoading] = useState(false); // 切换页码时获取对应页数据 const handlePageChange = async (event: React.ChangeEvent<unknown>, value: number) => { setIsLoading(true); setCurrentPage(value); const response = await fetch(`/api/data?page=${value}`); const newData = await response.json(); setData(newData); setIsLoading(false); }; return ( <div> {isLoading ? ( <p>加载中...</p> ) : ( data.map((item: Card) => ( <Cards key={item.id} data={item} /> )) )} <Pagination count={10} variant="outlined" shape="rounded" page={currentPage} onChange={handlePageChange} /> </div> ); }
步骤3:更新服务器组件传递初始数据
在page.tsx中预获取第一页数据,作为客户端组件的初始值:
// page.tsx export interface Card { id: number; name: string; } export default async function Home() { // 服务器端获取第一页数据,作为客户端初始加载内容 const initialData = await fetch( `https://api/data?key=${process.env.API_KEY}&page=1` ) .then(res => res.json()) .then(res => res.results); return ( <main> <ClientComponent initialData={initialData} /> </main> ); }
关键说明
- 密钥安全:所有外部API请求都通过内部路由发起,API_KEY仅在服务器端环境中使用,客户端永远不会接触到。
- 分页逻辑:客户端通过
useState管理当前页码,切换页码时触发新的内部API请求,更新数据列表。 - 性能优化:服务器端预加载第一页数据,避免客户端首次加载时的额外请求,提升首屏体验。
内容的提问来源于stack exchange,提问作者Ciaran Crowley
相关产品推荐
相关产品推荐

