Next.js 13 App Router API路由如何读取Public目录静态文件?
Next.js 13 App Router 图片加水印问题解决
针对你在App Router中给上传图片加水印时读取水印文件失败的问题,核心问题出在路径拼接错误和不必要的文件读取操作,以下是具体修正方案:
问题分析
- 水印文件路径拼接错误:
join(process.cwd(), "/public/wm.png")里的开头斜杠会导致路径异常,比如Windows系统下会直接指向磁盘根目录的public文件夹,而非项目根目录下的public目录。 - 多余的文件读取操作:sharp的
composite方法本身支持直接传入文件路径作为input,额外用readFile读取反而容易引发异步或路径类错误。
修正后的代码
// src/app/api/route.ts import { join } from 'path'; import { writeFile, mkdir } from 'fs/promises'; import sharp from 'sharp'; export async function handleImage(file: File) { try { const bytes = await file.arrayBuffer(); const buffer = Buffer.from(bytes); const isProduction = process.env.NEXT_PUBLIC_PRODUCTION === 'true'; let path: string; // 确保输出目录存在,避免写入失败 if (isProduction) { path = join('/', 'tmp', file.name); await mkdir(join('/', 'tmp'), { recursive: true }); } else { path = join(process.cwd(), 'public', 'tmp', file.name); await mkdir(join(process.cwd(), 'public', 'tmp'), { recursive: true }); } // 正确拼接水印文件路径 const watermarkPath = join(process.cwd(), 'public', 'wm.png'); // 直接传入水印路径给sharp,无需提前读取文件 const watermarkedBuffer = await sharp(buffer) .composite([{ input: watermarkPath, top: 50, left: 50 }]) .png({ quality: 80 }) .toBuffer(); await writeFile(path, watermarkedBuffer); const ImgTwitterId = await rwClient.v1.uploadMedia(path); return { path, mediaId: ImgTwitterId }; } catch (error) { console.error('加水印操作失败:', error); throw error; } }
关键修改点
- 路径修正:用
join(process.cwd(), 'public', 'wm.png')拼接水印路径,确保开发/生产环境都能正确定位到项目根目录下的public文件夹。 - 移除多余读取:直接将水印文件路径传入sharp的
composite方法,省去readFile步骤,减少出错环节。 - 目录预创建:添加
mkdir并设置recursive: true,确保输出目录存在,避免因目录不存在导致的写入失败。 - 环境变量判断优化:直接用
=== 'true'判断生产环境,避免不必要的类型转换。
额外注意事项
- 确保已安装sharp依赖:执行
npm install sharp或yarn add sharp完成安装。 - 生产环境中
/tmp是临时目录,建议定期清理生成的文件,避免磁盘占用过高。 - 开发环境下,public目录下的文件会被Next.js静态服务托管,但API路由操作的是本地文件系统,直接操作public目录是可行的。
内容的提问来源于stack exchange,提问作者Ihda Anwari
相关产品推荐
相关产品推荐

