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→multipleKeepExtentions→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
相关产品推荐
相关产品推荐

