Next.js调用Medium故事API时出现上游图片响应失败(403)问题求助
解决Next.js加载Medium图片时的403错误(upstream image response failed)
问题原因
你遇到的upstream image response failed + 403错误,本质是Medium的CDN启用了防盗链机制:它会校验请求的Referer和User-Agent字段,当Next.js的Image组件通过自身优化服务器发起请求时,请求头不符合Medium的安全规则,因此被拒绝访问。
解决方案
方案1:配置Next.js图片域名与自定义请求头
通过next.config.js配置允许Medium图片域名,并为代理请求添加合规的请求头,让Next.js的图片优化服务能正常拉取Medium图片:
- 修改
next.config.js:
/** @type {import('next').NextConfig} */ const nextConfig = { images: { remotePatterns: [ { protocol: 'https', hostname: 'cdn-images-1.medium.com', pathname: '/**', }, ], }, async headers() { return [ { source: '/_next/image(.*)', headers: [ { key: 'User-Agent', value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', }, { key: 'Referer', value: 'https://medium.com/', }, ], }, ]; }, }; module.exports = nextConfig;
- 重启Next.js开发服务器,让配置生效。
方案2:预加载图片为Base64格式
在静态生成阶段(getStaticProps)提前拉取图片并转换为Base64,直接传递给组件使用,绕开Medium的CDN防盗链:
- 修改
articles.jsx中的getStaticProps:
export async function getStaticProps() { const res = await fetch( `https://api.rss2json.com/v1/api.json?rss_url=https://medium.com/feed/@yasmine.daly` ); const data = await res.json(); // 批量转换图片为Base64 const processedArticles = await Promise.all( data.items.map(async (article) => { if (!article.thumbnail) return article; try { const imageRes = await fetch(article.thumbnail, { headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36', 'Referer': 'https://medium.com/' } }); const buffer = await imageRes.arrayBuffer(); const base64 = Buffer.from(buffer).toString('base64'); return { ...article, thumbnailBase64: `data:image/jpeg;base64,${base64}` }; } catch (err) { console.error(`加载图片失败 ${article.thumbnail}:`, err); return article; } }) ); return { props: { title: 'Articles', articles: processedArticles }, revalidate: 60, }; }
- 修改
ArticleCard.jsx中的Image组件:
<Image src={article.thumbnailBase64 || article.thumbnail} alt={article.title} width={300} height={150} />
方案3:使用原生img标签(临时应急)
如果不需要Next.js的图片优化功能,可以直接替换为原生img标签,部分场景下能绕过防盗链限制:
// 替换ArticleCard中的Image组件 <img src={article.thumbnail} alt={article.title} width={300} height={150} style={{ objectFit: 'cover', width: '100%', height: 'auto' }} crossOrigin="anonymous" />
方案选择建议
- 生产环境优先用方案1:保留Next.js图片优化的优势(压缩、格式转换、懒加载),同时合规访问Medium图片。
- 静态站点用方案2:预加载Base64图片,避免客户端请求时的防盗链问题,适合静态生成场景。
- 方案3仅作临时测试:原生img标签无法享受Next.js的图片优化能力,且仍可能被Medium的防盗链拦截。
内容的提问来源于stack exchange,提问作者Yasmine Daly
相关产品推荐
相关产品推荐

