NextJS组件中访问私有API密钥的最佳实践是什么?
正确隐藏API Key的最优实践
你当前的做法完全没有起到隐藏API Key的作用——客户端通过fetch你的API路由后,就能直接拿到API Key,和把它设为NEXT_PUBLIC_前缀的环境变量没区别。
核心原则:永远不要让敏感的API Key出现在客户端代码或响应中,所有需要用到API Key的请求,都应该由你的服务端来完成。
以下是两种可行的最优方案:
方案一:服务端组件直接传递(仅适用于组件为服务端组件的场景)
如果你的<Component>是服务端组件(默认不带'use client'标记的组件都是服务端组件),可以直接在服务端获取API Key并传递给它:
// app/page.tsx(服务端组件) import Component from './Component'; export default function Page() { // 这里在服务端读取环境变量,不会暴露给客户端 const apiKey = process.env.API_KEY; return <Component apiKey={apiKey} />; }
注意:如果
<Component>是客户端组件(带'use client'),绝对不能用这种方式——因为客户端组件的props会被序列化后发送到浏览器,API Key会直接暴露在客户端JS代码中。
方案二:创建代理API路由(客户端组件必选方案)
如果你的<Component>必须是客户端组件,正确的做法是:让客户端调用你自己的API路由,由服务端在这个路由内部带上API Key去调用第三方接口,再把第三方接口的结果返回给客户端,全程不暴露API Key。
步骤1:创建代理路由
// app/api/proxy-third-party/route.ts export async function GET(request: Request) { // 从客户端请求中获取需要的参数(比如接口所需的ID、参数等) const { searchParams } = new URL(request.url); const targetId = searchParams.get('id'); // 调用第三方接口,在服务端带上API Key const thirdPartyResponse = await fetch(`https://第三方接口地址?targetId=${targetId}`, { headers: { // 根据第三方接口要求传递API Key,比如Authorization头或自定义api-key头 'Authorization': `Bearer ${process.env.API_KEY}`, // 'api-key': process.env.API_KEY } }); const thirdPartyData = await thirdPartyResponse.json(); // 将第三方接口的结果返回给客户端,全程不暴露API Key return Response.json(thirdPartyData); }
步骤2:客户端组件调用代理路由
// app/Component.tsx(客户端组件) 'use client'; import { useState, useEffect } from 'react'; export default function Component() { const [data, setData] = useState(null); useEffect(() => { const fetchData = async () => { // 调用自己的代理路由,不需要处理API Key const response = await fetch('/api/proxy-third-party?id=123'); const result = await response.json(); setData(result); }; fetchData(); }, []); return ( <div> {data ? JSON.stringify(data) : '加载中...'} </div> ); }
关键注意事项
- 任何情况下,都不要把敏感API Key通过props、state、API响应等方式传递给客户端
- 非
NEXT_PUBLIC_前缀的环境变量只能在服务端代码中访问(服务端组件、API路由、Server Actions等) - 所有需要API Key的第三方请求,都应该由你的服务端作为中间层代理完成
内容的提问来源于stack exchange,提问作者Melv1nS
相关产品推荐
相关产品推荐

