如何在Next.js前端隐藏/保护API路由?
隐藏Next.js /api路由,禁止前端直接访问的方案
1. 限制请求来源(拦截非本站发起的请求)
在/api路由的处理函数中,通过验证请求的Origin或Referer头,只允许来自你自身前端域名的请求访问:
export default function handler(req, res) { const allowedOrigin = process.env.NEXT_PUBLIC_APP_URL; // 替换为你的前端域名,如https://your-app.com const origin = req.headers.origin || req.headers.referer; // 验证请求来源是否合法 if (!origin || !origin.startsWith(allowedOrigin)) { return res.status(403).json({ message: "禁止直接访问API" }); } // 正常业务逻辑 res.status(200).json({ data: "安全返回内容" }); }
注意:这种方法能挡住普通用户直接输入URL访问,但
Origin/Referer可被伪造,适合基础防护场景。
2. 改用服务器端专属逻辑(完全不暴露/api端点)
如果你的API仅用于Next.js内部(比如服务器组件、getServerSideProps、其他服务调用),可以把业务逻辑抽离到服务器端专属模块,彻底不创建/api路由:
// lib/api/user.js(仅服务器端可访问) export async function getUserData(userId) { // 直接操作数据库或第三方服务 return await db.user.findUnique({ where: { id: userId } }); }
在服务器组件中直接调用:
// app/user/[id]/page.js import { getUserData } from '@/lib/api/user'; export default async function UserPage({ params }) { const user = await getUserData(params.id); return <div>{user.name}</div>; }
这种方式完全不会对外暴露API端点,是最安全的方案。
3. 添加API密钥验证
在请求头中加入自定义密钥,仅允许携带有效密钥的请求访问API:
// /api/data.js export default function handler(req, res) { const apiKey = req.headers['x-api-key']; const validKey = process.env.API_SECRET_KEY; // 从环境变量读取密钥 if (!apiKey || apiKey !== validKey) { return res.status(401).json({ message: "无效的API密钥" }); } // 业务逻辑处理 res.status(200).json({ data: "安全数据" }); }
前端调用时在请求头中携带密钥:
async function fetchData() { const res = await fetch('/api/data', { headers: { 'x-api-key': process.env.NEXT_PUBLIC_API_KEY } }); const data = await res.json(); }
注意:前端暴露密钥存在被窃取风险,此方案更适合服务器端之间的调用。
4. 用Middleware全局拦截/api请求
在项目根目录创建middleware.js,统一拦截所有/api开头的请求,验证通过才允许访问:
import { NextResponse } from 'next/server'; export function middleware(request) { const allowedOrigin = process.env.NEXT_PUBLIC_APP_URL; const origin = request.headers.get('origin') || request.headers.get('referer'); if (request.nextUrl.pathname.startsWith('/api') && (!origin || !origin.startsWith(allowedOrigin))) { return new NextResponse(JSON.stringify({ message: "禁止直接访问" }), { status: 403, headers: { 'Content-Type': 'application/json' } }); } return NextResponse.next(); } export const config = { matcher: '/api/:path*', // 匹配所有/api路由 };
这种方式无需在每个/api路由中单独写验证逻辑,实现全局统一防护。
内容的提问来源于stack exchange,提问作者Raghav Patel
相关产品推荐
相关产品推荐

