網站搜尋

typescript - 如何清除 NextJs GetStaticPaths 的快取/「取消發布」一個動態路由?


我覺得這問題相當普通,但我在 Google 上找不到任何資料。

我正在學習 NextJs(使用 TypeScript),我已經成功建立了一個網站,支援動態路由、伺服器端渲染(SSR)和增量再生(Incremental Regeneration),並已部署到 Vercel。這裡是一個我在動態路由處理器中使用的 GetStaticProps 和 GetStaticPaths 範例代碼:

export const getStaticPaths: GetStaticPaths = async () => {
    const routes = new CmsHelper().GetRoutes();

    const paths = (await routes).items.map((item, index, items) => {
        return item.fields.urlPath;
    })

    return {
        paths: paths,
        fallback: 'blocking',
    };
}

export const getStaticProps: GetStaticProps = async (context) => {
    const urlParts = context.params?.url as string[] || [];
    const urlPath = `/${urlParts.join('/')}`;
    const article = await new CmsHelper().GetArticle(urlPath);
    return {
        props: {
            article
        },
        revalidate: 10,
    }
}

如果我請求一個在建置時間之後於 CMS 發佈的新路徑,它會在伺服器上成功重新生成並返回該頁面。

到目前為止一切順利。

然而,如果我在我的 CMS 中 取消發布 一個路由……它仍然會被應用返回,除非我重新構建和重新部署(或者在開發中以其他方式使進程重啟)。

所以我的問題是:我該如何動態地讓 NextJs 從它的 GetStaticPaths 快取中移除一個動態路由?

我理解因為 revalidate 設定,GetStaticProps 最多每 10 秒會被呼叫一次。但據我所知,GetStaticPaths 只有在來自目前尚未快取的路由的請求時才會被呼叫(?)

換句話說,對於與無頭 CMS 的整合,我如何在不觸發重建/部署的情況下,使用 NextJs 支援 取消發布或重新命名 頁面?

提前感謝你!

答案#1

也許可以嘗試這裡描述的方法。

這裡也提供程式碼以供參考。

// pages/blog/[slug].js

import {useRouter} from 'next/router'
import DefaultErrorPage from 'next/error'

export async function getStaticProps({ params }) {
  // fetch data from CMS through params
  const post = await getBlogItem(params.slug)
  return {
    props: {
      post
    }
  }
}

export async function getStaticPaths() {
  return {
    fallback: true,
    paths: []
  }
}

export default function MyPage({post}) {
  const router = useRouter()

  if(router.isFallback) {
     return <h1>Loading...</h1>
  }

  // This includes setting the noindex header because static files always return a status 200 but the rendered not found page page should obviously not be indexed
  if(!post) {
    return <>
      <Head>
        <meta name="robots" content="noindex">
      </Head>
      <DefaultErrorPage statusCode={404} />
    </>
  }

  return <h1>{post.title}</h1>
}

所以,與其刪除/清除快取,不如嘗試成功處理你正在取得的內容是“未發佈”的情況,如果是這樣,你可以顯示一個 404 Not found 頁面或其他你選擇的內容。

像這樣的東西:

export async function getStaticProps(context) {

    const {params: {id}} = context

    let data;
    try {
        data = await httpClient...
    } catch (err) {
        if (not err is caused due to content being unpublished){
            // re throw it
            throw err;
        }
        // Else handle it gracefully
        data = null;
    }

    return {
        props: {
            data,
        },
        revalidate: 1
    };
}

然後在你的視圖上:

export default function Data(props) {
    const {data} = props;

    const router = useRouter()

    // If the page is not yet generated, this will be displayed
    // initially until getStaticProps() finishes running
    if (router.isFallback) {
        return <div>Loading...</div>
    }

    if (!data) {
        return (
            <>
                <Head>
                    <meta name="robots" content="noindex"/>
                </Head>
                <DefaultErrorPage statusCode={404}/>
            </>
        )
    }

    return <DataView {...data} />;

}

答案#2

我面臨了一個類似但不同的問題:部署我的項目從數據生成的 URL,但當資料庫中的數據變更時,我無法添加任何新的 URL。

我問題的關鍵在於我在 getStaticPaths 方法中將 fallback 設為 false。當我將其設為 true 時,生產部署開始像我的本地開發構建一樣運行。

我看到你正在為你的 fallback 屬性傳遞一個字串值。你可以嘗試使用這裡描述的布林值:https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required