Next.js(TypeScript) API本地正常,Vercel生产环境超时问题求助
问题:Next.js + Firebase API在Vercel生产环境超时,仅单个参数可用
- 基于Next.js(TypeScript)搭建站点,API在开发环境正常,部署到Vercel生产环境后出现超时
- API接收三个可选参数,但仅其中一个值在生产环境能正常返回数据
- 需一次性获取全量数据生成图表,无法分页,数据源为Google Firebase
API路由代码(app/api/google/getFirestoreData/route.ts)
import { googleDb } from "@/lib/firebase"; import { Query, DocumentData } from "firebase-admin/firestore"; import { NextRequest, NextResponse } from "next/server"; type Data = { documentId: string; [key: string]: any; }; export async function GET( req: NextRequest, ) { if (!googleDb) { console.error("Problem with googleDb") return new NextResponse("Firebase Firestore is not initialized", { status: 500 }); } const paramName = req.nextUrl.searchParams.get("paramName"); try { const collectionRef = googleDb.collection("collectionName") let query: Query<DocumentData> = collectionRef; if (kingdom !== "n") { query = query.where("creteria", "==", paramName as string); } const querySnapshot = await query.get() if (querySnapshot.empty) { console.error("No matching documents found."); return new NextResponse("No matching documents found", { status: 500 }); } const data: Data[] = []; querySnapshot.forEach((doc) => { data.push({ documentId: doc.id, ...doc.data() }); }); return new NextResponse(JSON.stringify({ data }), { status: 200, headers: { "Content-Type": "application/json" } }); } catch (error) { console.error(`Error fetching data from Firestore: ${error}`); return new NextResponse("Initial Server Error", { status: 500 }); } }
前端API调用代码
useEffect(() => { const fetchFirestoreData = async () => { try { const data = await fetchData("/api/google/getFirestoreData?kingdom=n"); setFirestoreData(data); filterData(data.data); } catch (error) { setError({ message: error } as { message: string }); } finally { setIsLoading(false); } }; fetchFirestoreData(); }, []);
fetchData工具函数
import { toast } from "react-toastify"; const fetchData = async ( url: string, options = {} ) => { try { const fetchWithTimeout = (timeoutMs: number) => { return Promise.race([ fetch(url, { cache: 'force-cache' }), new Promise<never>((_, reject) => setTimeout(() => reject(new Error("API timed out")), timeoutMs) ) ]); }; const response = await fetchWithTimeout(30000); return response.json(); } catch (error) { toast.error(`Error retrieving data: ${error}`); throw new Error('Could not get data') } } export { fetchData };
排查与解决建议
1. 修复API路由中的参数与拼写错误
- 前端传参为
kingdom,但API中错误获取paramName,需修正参数获取逻辑:const kingdom = req.nextUrl.searchParams.get("kingdom"); if (kingdom !== "n" && kingdom) { query = query.where("criteria", "==", kingdom); } - 代码中
creteria是拼写错误,需改为正确的字段名criteria(如果Firestore中字段名为此),否则会导致查询无结果进而超时。
2. 优化Firestore查询性能
- 检查Firestore控制台,确认
criteria字段的查询索引是否存在,无索引会导致大数据量查询超时 - 使用
select()方法只获取生成图表必需的字段,减少数据传输量:query = query.where("criteria", "==", kingdom).select("requiredField1", "requiredField2"); - 在Firestore控制台开启查询性能监控,查看生产环境查询的耗时详情。
3. 调整Vercel函数超时配置
- Vercel Serverless Function默认超时为10秒,前端设置的30秒超时无意义,需在Vercel项目设置中将函数超时调整至最大90秒
- 确认Firebase Admin SDK在Vercel生产环境中已正确初始化,检查相关环境变量(如密钥文件配置)是否齐全。
4. 调整缓存策略
- 前端
fetch使用cache: 'force-cache'可能缓存错误响应,动态数据建议改为:fetch(url, { cache: 'no-store' }) - 或在API路由中设置缓存头,控制生产环境缓存行为:
return new NextResponse(JSON.stringify({ data }), { status: 200, headers: { "Content-Type": "application/json", "Cache-Control": "no-store, max-age=0" } });
5. 查看生产环境日志
- 登录Vercel控制台,查看对应Serverless Function的执行日志,获取后端真实错误信息(如Firestore权限问题、查询超时详情)
- 在API代码中增加更详细的日志,辅助排查:
console.log(`Query criteria: ${kingdom}`); console.log(`Fetched ${querySnapshot.size} documents`);
内容的提问来源于stack exchange,提问作者Matan Naydis
相关产品推荐
相关产品推荐

