如果我通过表单上传图像,然后想通过 next.js api 获取它并通过图像组件显示,我会收到 400 Bad Request 响应。图像组件显示“无法加载图像”。尝试在配置中指定域并使用Loader,结果相同。更重要的是,我无法直接通过浏览器网址栏访问新上传的图像。但是,如果我重建项目,那些以前上传的图像最终会显示,并且不会出现 400 错误。我将图像上传到
/public/uploads
目录中。此问题仅在生产模式下发生(npm run build
,npm run start
)。当我在本地开发模式下使用它时,没有这样的问题(npm run dev
)。如何在不重建项目的情况下让新上传的图片正确显示?
总结
我也遇到了这个问题。我正在将临时图像上传到
public/_i
。在使用 next run dev
进行开发期间,一切看起来都很棒,但是一旦我在产品模式下构建并运行,我就开始看到:
⨯ The requested resource isn't a valid image for /_i/f7e5c4f31c368fc46057fd55bf8c066c.jpeg received text/html; charset=utf-8
我研究了 loaders 并为该路径设置了 custom headers 。都没有效果。
事实证明,**Next.JS 鼓励将动态内容上传到单独的服务或 CDN。 ** 他们不鼓励像这样动态地提供图像内容,并且它可能被认为是一种反模式。在图像优化页面下,他们做了这样的说明:
图像占典型网站页面权重的很大一部分,并且会对网站的 LCP 性能产生相当大的影响
您的内容在重建后出现这一事实证明了这一点。这是因为构建系统已缓存您上传的图像,就好像它是静态内容一样。
尽管如此,如果您(像我一样)想继续,这就是我所做的:
import fs from 'fs';
import path from 'path';
export async function GET(request: Request) {
if (!process.env.IMAGE_UPLOAD_PUBLIC_PATH) {
throw new Error('IMAGE_UPLOAD_PUBLIC_PATH is not set');
}
const url = new URL(request.url);
const image = url.searchParams.get('key');
if (image?.trim()) {
const imagePath = path.join('public', process.env.IMAGE_UPLOAD_PUBLIC_PATH, `${image}.jpeg`);
if (fs.existsSync(imagePath)) {
const buffer = fs.readFileSync(imagePath);
return new Response(buffer, {
headers: {
'Content-Type': 'image/png',
},
});
} else {
return new Response('', { status: 404 });
}
}
return new Response('', { status: 400 });
}
<Image />
替换为常规 <img />
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={`/api/image?key=${image}`} className="h-full w-full" />
这应该就是您所需要的。