You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js图片优化未缓存Notion图片求助(Next 13 appDir)

解决方案:Notion 托管图片在 Next.js 13 App Dir 中的持久化处理

针对你遇到的 Notion 媒体链接1小时过期、ISR 和 next/image 缓存不生效的问题,给你几个可行的本地解决方案(无需外部图片托管):

1. 自建图片代理 Route Handler

在 Next.js 中创建专门的图片代理接口,通过服务器中转请求并缓存图片,绕过 Notion 的临时链接限制:

  • 在 app/api/proxy-image/[...path]/route.ts 编写代理逻辑:
    import { NextResponse } from 'next/server';
    
    export async function GET(request: Request) {
      const { searchParams } = new URL(request.url);
      const notionUrl = searchParams.get('url');
      if (!notionUrl) return new NextResponse('Missing URL', { status: 400 });
    
      const response = await fetch(notionUrl);
      if (!response.ok) return new NextResponse('Failed to fetch image', { status: response.status });
    
      // 设置缓存头,强制浏览器和CDN缓存图片30天
      const headers = new Headers(response.headers);
      headers.set('Cache-Control', 'public, max-age=2592000, s-maxage=2592000');
      headers.delete('expires');
      headers.delete('pragma');
    
      return new NextResponse(response.body, { headers });
    }
    
    // 启用Edge Runtime提升代理性能(可选)
    export const runtime = 'edge';
    
  • 在页面中用代理链接替换原始 Notion 链接:
    import Image from 'next/image';
    
    export default function Post({ post }) {
      const proxyImageUrl = `/api/proxy-image?url=${encodeURIComponent(post.imageUrl)}`;
      return <Image src={proxyImageUrl} alt={post.title} width={800} height={600} />;
    }
    

核心是通过自有的服务器中转图片请求,把临时的 Notion 链接转换成长期可访问的代理链接,同时通过缓存头锁定图片内容。

2. 优化 ISR 重验证时机 + 客户端兜底

调整 ISR 周期并配合图片加载失败处理,避免显示过期图片:

  • 在页面组件中设置小于60分钟的重验证时间,确保链接过期前完成页面更新:
    export const revalidate = 3300; // 55分钟,单位秒
    
  • 给图片添加错误回调,加载失败时主动拉取最新链接:
    import Image from 'next/image';
    import { useState } from 'react';
    
    export default function Post({ initialImageUrl, postId }) {
      const [imageUrl, setImageUrl] = useState(initialImageUrl);
    
      const handleImageError = async () => {
        const res = await fetch(`/api/get-latest-image?postId=${postId}`);
        const data = await res.json();
        setImageUrl(data.latestImageUrl);
      };
    
      return <Image src={imageUrl} alt={post.title} width={800} height={600} onError={handleImageError} />;
    }
    

这里的 /api/get-latest-image 接口需要直接从 Notion API 拉取对应文章的最新数据,返回有效图片链接。

3. Edge 层缓存图片元数据

利用 Next.js 的 Edge Runtime 缓存图片链接,每次渲染前先检查链接是否即将过期:

  • 在获取 Notion 数据的函数中添加缓存逻辑:
    import { cache } from 'react';
    
    export const getNotionPost = cache(async (postId: string) => {
      const cacheKey = `notion-post-${postId}`;
      const cachedData = await caches.default.match(cacheKey);
      
      if (cachedData) {
        const data = await cachedData.json();
        // 检查链接是否还在有效期内(提前5分钟触发更新)
        const now = Date.now();
        if (now - data.fetchTime < 55 * 60 * 1000) {
          return data;
        }
      }
    
      // 从Notion API重新拉取数据
      const res = await fetch(`https://api.notion.com/v1/pages/${postId}`, {
        headers: { Authorization: `Bearer ${process.env.NOTION_TOKEN}` },
      });
      const data = await res.json();
      const dataWithFetchTime = { ...data, fetchTime: Date.now() };
    
      // 缓存数据55分钟,同时允许后台异步更新
      const response = new Response(JSON.stringify(dataWithFetchTime), {
        headers: { 'Cache-Control': 's-maxage=3300, stale-while-revalidate=300' },
      });
      await caches.default.put(cacheKey, response);
    
      return dataWithFetchTime;
    });
    

通过 Edge 层缓存优先使用未过期的链接,同时在后台异步更新数据,规避 stale-while-revalidate 带来的旧链接问题。


内容的提问来源于stack exchange,提问作者lw_101

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:15:00