You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:03:19