使用Next.js 12 API路由获取受保护图片至Next Image组件是否可行?
问题描述
后端图片受Basic Authentication保护,由于Next.js 12的Image组件不支持设置自定义HTTP请求头,我通过创建Next.js API路由来为请求添加Basic Auth请求头,并将该路由作为Image组件的图片地址,代码如下:
API路由代码(pages/api/image/index.ts)
export default async function handler( req: NextApiRequest, res: NextApiResponse ) { const id = req.query.id; const response = await axios({ method: "get", url: `https://protected-images.com/images/${id}`, responseType: "stream", headers: { Authorization: `Basic ${decodeURIComponent(token)}`, }, }); response.data.pipe(res); }
Image组件使用代码
<Image src={`/api/image/${id-of-protected-image}`} alt={title || ""} layout={"fill"} objectFit={objectFit} objectPosition={objectPosition} className={className || ""} />
请问:
- 该方案是否会导致Vercel平台上无服务器函数的使用率过高?
- 这是Next.js 12中渲染受保护图片的可行方案吗?
- 是否存在替代方案?
回答
1. 是否会导致Vercel无服务器函数使用率过高?
会有明显的风险。因为每一次图片请求都会触发一次API路由的无服务器函数调用:
- 页面包含多张图片、或者有大量用户访问时,函数调用次数会快速累积
- Vercel的免费/基础套餐有函数调用次数限制,超出后会产生额外费用或限制服务
- 哪怕是付费套餐,高频调用也会增加成本,而且函数冷启动还可能拖慢图片加载速度
2. 是否是Next.js 12中渲染受保护图片的可行方案?
属于临时能用但不适合长期用的方案:
- 功能上确实能实现需求,正常加载受Basic Auth保护的图片
- 但缺陷很突出:函数调用成本高、多了一次中转请求导致性能损耗、默认没有缓存优化(每一次请求都要重新从后端拉取图片)
3. 替代方案
方案一:用原生img标签配合fetch获取Blob
如果不需要Next Image的自动优化功能,可以直接用原生<img>标签,先通过fetch带Auth头获取图片Blob,再转成Data URL使用:
import { useState, useEffect } from 'react'; function ProtectedImage({ id, alt }) { const [imageUrl, setImageUrl] = useState(''); useEffect(() => { const fetchImage = async () => { const response = await fetch(`https://protected-images.com/images/${id}`, { headers: { Authorization: `Basic ${decodeURIComponent(token)}`, }, }); const blob = await response.blob(); setImageUrl(URL.createObjectURL(blob)); }; fetchImage(); return () => URL.revokeObjectURL(imageUrl); }, [id]); return <img src={imageUrl} alt={alt} />; }
注意:这种方式没法用Next Image的优化特性,大图片还会占用较多前端内存。
方案二:用Vercel中间件配合Image优化
如果后端图片服务允许Vercel的优化服务访问,可以在next.config.js里把受保护域名加入白名单,再通过中间件给图片请求注入Auth头:
// next.config.js module.exports = { images: { domains: ['protected-images.com'], }, };
然后创建middleware.js(Next.js 12.2及以上版本支持):
export function middleware(req) { if (req.nextUrl.pathname.startsWith('/_next/image')) { const targetUrl = new URL(req.nextUrl.searchParams.get('url')); return fetch(targetUrl.toString(), { headers: { Authorization: `Basic ${decodeURIComponent(token)}`, }, }); } return NextResponse.next(); }
这种方式能保留Next Image的优化功能,同时大幅减少无服务器函数的调用次数。
方案三:构建时预拉取图片到静态资源
如果图片内容不频繁更新,可以在项目构建阶段预先拉取所有受保护图片,放到public目录下,之后直接用静态地址引用:
- 在
next.config.js里添加构建脚本,把图片拉取到public/images目录 - Image组件直接引用
/images/${id}路径
这种方式完全避免了函数调用,性能最优,但只适合静态或低频更新的图片。
内容的提问来源于stack exchange,提问作者Sushant Rajbanshi
相关产品推荐
相关产品推荐

