Next.js生产环境静态资源上传后返回404问题
Next.js生产环境上传图片后无需重启即可访问的解决方案
问题原因
Next.js在生产构建阶段会将public目录下的所有资源进行静态优化、打包并缓存,运行时不会动态监测public目录的文件变化。因此上传到public的新文件无法被Next.js的静态服务识别,必须重启服务器重新加载资源才能访问。而开发模式下Next.js会实时监测文件系统变化并热重载,所以能直接访问新上传的文件。
解决方案
1. 改用独立的上传目录
不要将上传文件放到public目录,在项目根目录创建独立的uploads/img目录存储上传的图片。
2. 修改上传API路由代码
更新上传逻辑,将文件移动到新的上传目录,并处理错误:
import { IncomingForm } from "formidable"; import { v4 } from "uuid"; const mv = require("mv"); import fs from "fs"; import path from "path"; export const config = { api: { bodyParser: false, }, }; // 确保上传目录存在,不存在则创建 const uploadDir = path.join(process.cwd(), "uploads", "img"); if (!fs.existsSync(uploadDir)) { fs.mkdirSync(uploadDir, { recursive: true }); } export default async (req, res) => { const imageId = v4(); const form = new IncomingForm(); form.parse(req, (err, fields, files) => { if (err) { return res.status(500).json({ error: err.message }); } const oldPath = files.file.filepath; const fileExt = path.extname(files.file.originalFilename); const newImageId = `${imageId}${fileExt}`; const newPath = path.join(uploadDir, newImageId); mv(oldPath, newPath, (err) => { if (err) { return res.status(500).json({ error: err.message }); } // 返回可访问的图片URL res.status(200).json({ fields, files, imageId: newImageId, imageUrl: `/api/uploads/img/${newImageId}` }); }); }); };
3. 创建文件访问API路由
在pages/api/uploads/img/[id].js(App Router对应app/api/uploads/img/[id]/route.js)创建路由,处理上传图片的访问请求:
// Pages Router版本 import fs from "fs"; import path from "path"; export default function handler(req, res) { const { id } = req.query; const filePath = path.join(process.cwd(), "uploads", "img", id); if (!fs.existsSync(filePath)) { return res.status(404).json({ error: "图片不存在" }); } // 根据文件后缀设置正确的Content-Type const ext = path.extname(filePath).toLowerCase(); let contentType = "image/jpeg"; if (ext === ".png") contentType = "image/png"; else if (ext === ".gif") contentType = "image/gif"; else if (ext === ".webp") contentType = "image/webp"; res.setHeader("Content-Type", contentType); fs.createReadStream(filePath).pipe(res); }
4. 可选:配置路由重写(更友好的URL)
在next.config.js中添加重写规则,让前端可以用更简洁的URL访问图片:
/** @type {import('next').NextConfig} */ const nextConfig = { async rewrites() { return [ { source: "/uploads/img/:path*", destination: "/api/uploads/img/:path*", }, ]; }, }; module.exports = nextConfig;
配置后,前端可以通过/uploads/img/xxx.jpg直接访问上传的图片,无需拼接API路由路径。
注意事项
- 确保生产环境中Node.js进程拥有
uploads目录的读写权限。 - 可以考虑添加文件大小、类型校验,避免非法文件上传。
- 若使用App Router,需调整API路由的写法(使用
NextResponse等)。
内容的提问来源于stack exchange,提问作者Filip Gurak
相关产品推荐
相关产品推荐

