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

Next.js中如何通过指定URL结构访问public文件夹内的文件

问题解答

能否通过mydomain.com/public/coverimg/image.jpg访问文件?

不能。Next.js的public目录是静态资源的根目录,访问其中的文件时不需要在URL中添加/public前缀。正确的访问路径应该是:
mydomain.com/coverimg/[时间戳]/[图片ID]_文件名.jpg

比如你上传的文件存在public/coverimg/01_10_2024/abc123_test.jpg,那么访问URL就是mydomain.com/coverimg/01_10_2024/abc123_test.jpg。

你的API代码存在的问题及修正建议

1. 目录创建的错误处理逻辑缺陷

当前用fs.mkdir的回调直接res.send(err),会导致两个问题:

  • 目录创建成功时,无任何后续处理,请求会一直挂起
  • 目录创建失败时,直接返回错误但后续文件上传逻辑仍会执行

建议改用异步的fs.promises.mkdir配合try/catch处理:

try {
  await fs.promises.mkdir(`./public/coverimg/${timeStamp}`, { recursive: true });
} catch (err) {
  return res.status(500).json({ error: '创建目录失败', details: err.message });
}

2. Formidable配置项拼写错误

代码里的几个配置项拼写错误,会导致配置不生效:

  • multple → multiple
  • KeepExtentions → keepExtensions(formidable配置项为小驼峰,大小写敏感)
  • KeepFileName → keepFilename

3. 缺少请求响应

处理完文件上传后,代码未给客户端返回任何响应,会导致请求长期挂起。需在文件解析完成后添加响应逻辑:

const data = await new Promise(/* 你的form解析逻辑 */);

// 返回上传成功信息与访问URL
const uploadedFile = Object.values(data)[0];
const fileUrl = `/coverimg/${timeStamp}/${path.basename(uploadedFile.path)}`;
return res.status(200).json({
  success: true,
  fileUrl,
  file: uploadedFile
});

4. 导入语法混用问题

代码同时使用import和require,建议统一为ES模块语法:

import fs from 'fs/promises'; // 直接使用Promise版本,避免回调
import moment from 'moment';
import formidable from 'formidable-serverless';
import slugify from 'slugify';
import path from 'path';
import crypto from 'crypto';

修正后的完整代码示例

import fs from 'fs/promises';
import moment from 'moment';
import formidable from 'formidable-serverless';
import slugify from 'slugify';
import path from 'path';
import crypto from 'crypto';

export const config = {
  api: {
    bodyParser: false,
  },
};

const handler = async (req, res) => {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: '仅支持POST请求' });
  }

  const timeStamp = moment().format('DD_MM_YYYY');
  const imageId = crypto.randomBytes(16).toString('hex');

  try {
    // 创建存储目录
    await fs.mkdir(`./public/coverimg/${timeStamp}`, { recursive: true });
  } catch (err) {
    return res.status(500).json({ error: '创建存储目录失败', details: err.message });
  }

  try {
    const data = await new Promise((resolve, reject) => {
      const form = formidable({
        multiple: false,
        uploadDir: `./public/coverimg/${timeStamp}`,
        keepExtensions: true,
        keepFilename: true,
        maxFields: 1000
      });

      form.on('fileBegin', function (name, file) {
        file.path = path.join(
          `./public/coverimg/${timeStamp}`,
          `${imageId}_${slugify(file.name)}`
        );
      });

      form.parse(req, (error, fields, files) => {
        if (error) return reject(error);
        resolve(files);
      });
    });

    // 返回上传结果
    const uploadedFile = Object.values(data)[0];
    const fileUrl = `/coverimg/${timeStamp}/${path.basename(uploadedFile.path)}`;
    return res.status(200).json({
      success: true,
      fileUrl,
      fileInfo: {
        name: uploadedFile.name,
        size: uploadedFile.size,
        type: uploadedFile.type
      }
    });
  } catch (err) {
    return res.status(500).json({ error: '文件上传失败', details: err.message });
  }
};

export default handler;

内容的提问来源于stack exchange,提问作者Mr Right

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:10:15