NextJS API路由本地正常,Vercel部署后数据插入异常求助
问题
我的NextJS API路由在本地运行完全正常,调用后可在本地数据库中创建200+条记录,但部署到Vercel后出现异常:插入的记录数完全随机,有时0条、有时3条、有时55条。相关API路由代码如下:
import type { NextApiRequest, NextApiResponse } from "next"; import axios from "axios"; import prisma from "../../../lib/prisma"; interface Platform { id: number; abbreviation: string; alternative_name: string; category: number; created_at: number; generation: number; name: string; platform_logo: { id: number; alpha_channel: boolean; animated: boolean; height: number; image_id: string; url: string; width: number; checksum: string; }; slug: string; summary: string; updated_at: number; url: string; versions: number[]; checksum: string; } export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const url = "https://api.igdb.com/v4/platforms"; const headers = { "client-id": process.env.TWITCH_IGDB_CLIENT_ID, authorization: "Bearer my_token", "accept-encoding": "*", }; const body = `fields *, platform_family.*, platform_logo.*; limit 500;`; const response = await axios.post(url, body, { headers }); console.log("The response status is:", response.status); if (response.status == 200) { await response.data.forEach(async (p: Platform) => { try { const platform = await prisma.platform .create({ data: { category: p.category, name: p.name, slug: p.slug, platform_logo_url: p.platform_logo?.url, // Todo, sanitize this url. hashtag: p.name, // Todo, convert name to hashtag }, }); console.log("Created platforms", platform); } catch (e) { console.log(e) } }); } else { console.log(response.status); } res.status(200).json({ message: "Imported all platforms." }); }
原因分析
问题根源在于**forEach不支持异步函数的等待机制**:
forEach会遍历数组并立即触发每个异步插入操作,但它不会等待这些异步操作完成,而是直接继续执行后续代码。- 本地环境中,Node.js进程会持续运行直到所有异步任务结束,所以所有插入都能完成。
- 但Vercel的Serverless函数有严格的生命周期:当
handler函数执行到res.status(200).json(...)并返回响应后,函数进程会被立即终止,此时forEach中未完成的异步插入操作会被强制中断,导致插入记录数随机。
解决方案
将forEach替换为Promise.all,确保所有异步插入操作全部完成后再返回响应:
import type { NextApiRequest, NextApiResponse } from "next"; import axios from "axios"; import prisma from "../../../lib/prisma"; interface Platform { id: number; abbreviation: string; alternative_name: string; category: number; created_at: number; generation: number; name: string; platform_logo: { id: number; alpha_channel: boolean; animated: boolean; height: number; image_id: string; url: string; width: number; checksum: string; }; slug: string; summary: string; updated_at: number; url: string; versions: number[]; checksum: string; } export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const url = "https://api.igdb.com/v4/platforms"; const headers = { "client-id": process.env.TWITCH_IGDB_CLIENT_ID, authorization: "Bearer my_token", "accept-encoding": "*", }; const body = `fields *, platform_family.*, platform_logo.*; limit 500;`; const response = await axios.post(url, body, { headers }); console.log("The response status is:", response.status); if (response.status == 200) { // 将forEach替换为Promise.all,等待所有插入操作完成 await Promise.all(response.data.map(async (p: Platform) => { try { const platform = await prisma.platform.create({ data: { category: p.category, name: p.name, slug: p.slug, platform_logo_url: p.platform_logo?.url, hashtag: p.name, }, }); console.log("Created platform", platform); } catch (e) { console.error("Failed to create platform:", e); } })); } else { console.error("IGDB API response status:", response.status); return res.status(response.status).json({ error: "Failed to fetch platforms" }); } res.status(200).json({ message: "Imported all platforms." }); }
额外优化建议:
- 把硬编码的
"Bearer my_token"替换为环境变量,比如process.env.TWITCH_IGDB_ACCESS_TOKEN,避免敏感信息泄露。 - 可以考虑使用批量插入(如Prisma的
createMany)来减少数据库请求次数,提升效率并降低超时风险。
内容的提问来源于stack exchange,提问作者Only Bolivian Here
相关产品推荐
相关产品推荐

