You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在客户端组件中获取数据且不暴露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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 15:18:32