NEXT.js ISR 删除静态页面

Dav*_*vid 6 reactjs contentful next.js

我的 ISR 有一点问题。我的 revalidate 属性等于 1s,如下所示

export async function getStaticProps({ params }) {
  const data = await client.getEntries({
     content_type: "product",
    "fields.name": params.slug,
  });


  if (!data.items[0]) {
    return {
      notFound: true,
    };
  }
  return {
    props: {
      article: data.items[0],
      revalidate: 1,
    },
  };
}
Run Code Online (Sandbox Code Playgroud)

当我在 Contentful 中创建产品时,页面会按我的预期创建。当我想进入不存在的页面时,我会收到预期的 404 错误。当我更改现有产品中 Contentful 中的某些内容或将其删除时,问题就会出现。

当我在 Contentful 中删除产品时,产品页面中的产品列表会更新并且产品会消失,但我仍然可以进入该产品的页面。此外,当我重命名产品名称时,产品列表也会更新,但我仍然可以访问较早的页面名称。

有什么办法可以解决这个问题吗?

获取静态路径

export async function getStaticPaths() {
  const data = await client.getEntries({
    content_type: "product",
  });

  return {
    paths: data.items.map((item) => ({
      params: { slug: item.fields.name },
    })),
   fallback: true,
 };
}
Run Code Online (Sandbox Code Playgroud)

产品页面

const Article = ({ article }) => {
  const router = useRouter();

  if (router.isFallback) return <p>Loading...</p>;

  return (
    <div>
      <h1>Hello! {article.fields.name}</h1>
      <Link href="/about">
        <a>Back to about!</a>
      </Link>
    </div>
  );
};
Run Code Online (Sandbox Code Playgroud)

编辑 当我在 Contentful 中将产品名称从“product77”更改为“product7”时,重新验证我的产品77版本中的静态页面仍然存在,并且我仍然可以进入该页面。 在此输入图像描述

重新验证后不是应该删除吗?

Tan*_*kom 5

已删除的页面无法删除,但会出现 404 错误。一个人必须使用

下面的示例使用条目 id 来构建路径,例如example.com/post/90803230238。对于非 ID 路径,例如使用自定义字段example.com/post/how-to-make-icecream,请阅读本答案末尾的注释。

这样做的先决条件是 getStaticPathsgetStaticProps进行相应的配置。

// /pages/blog/[...post].jsx

function Post({ postData }) {
    return (
        // ...
    );
}

// Only runs once during build
export async function getStaticPaths() {
    const res = await fetch("https://.../posts");
    const posts = await res.json();

    // Prerender paths during build
    const paths = posts.map((post) => ({
        params: { post: post.id },
    }));

    return { 
        paths, 
        fallback: "blocking" // must be "blocking"
    };
}

// Runs during build and every revalidation
export async function getStaticProps(context) {
    const res = await fetch(`https://.../posts/${context.params.post}`);
    const postData = await res.json();

    // Check if the page exists in the CMS using the API response
    if(!postData){
        // The page doesn't exist in the CMS, return notFound to trigger a 404
        return{
            notFound: true,
            // Pick one of the following
            revalidate: 30, // <- ISR, interval in seconds between revalidations
            revalidate: false // On-demand
        }
    }

    // Return page props
    return {
        props: {
            postData,
        },
        // Pick one of the following
        revalidate: 30, // <- ISR, interval in seconds between revalidations
        revalidate: false // On-demand
    };
}
Run Code Online (Sandbox Code Playgroud)

上述代码的主要要点是:

  • 您可以预渲染getStaticPaths仅在初始构建期间运行的路径
  • getStaticPaths必须用作"blocking"fallback
  • getStaticProps它在初始构建和每次重新验证期间运行,每次都应该通过 API 请求询问页面状态(已发布、未发布,...) - 如果页面处于活动状态,则返回页面属性 - 如果页面处于非活动/已删除状态, 返回 a notFound:true, 回退到./pages/404.jsx页面

按需重新验证需要一个额外的文件,即 Webhook 可以向其发送通知的 API 端点。

// /pages/blog/[...post].jsx

function Post({ postData }) {
    return (
        // ...
    );
}

// Only runs once during build
export async function getStaticPaths() {
    const res = await fetch("https://.../posts");
    const posts = await res.json();

    // Prerender paths during build
    const paths = posts.map((post) => ({
        params: { post: post.id },
    }));

    return { 
        paths, 
        fallback: "blocking" // must be "blocking"
    };
}

// Runs during build and every revalidation
export async function getStaticProps(context) {
    const res = await fetch(`https://.../posts/${context.params.post}`);
    const postData = await res.json();

    // Check if the page exists in the CMS using the API response
    if(!postData){
        // The page doesn't exist in the CMS, return notFound to trigger a 404
        return{
            notFound: true,
            // Pick one of the following
            revalidate: 30, // <- ISR, interval in seconds between revalidations
            revalidate: false // On-demand
        }
    }

    // Return page props
    return {
        props: {
            postData,
        },
        // Pick one of the following
        revalidate: 30, // <- ISR, interval in seconds between revalidations
        revalidate: false // On-demand
    };
}
Run Code Online (Sandbox Code Playgroud)

使用res.revalidate(``/${reqBody.path}``)来自 的逻辑调用页面的新评估getStaticProps

现在,如果有人删除 CMS 中的页面,并为已删除的页面路径触发上述重新验证 Webhook 处理程序,则该路径将提供 404 页面而不是原始页面。

但是,页面本身不会从磁盘中删除。


使用路径的非 ID 自定义字段值重新验证

在 Contentful 中,在“取消发布”Webhook 通知期间,type: "DeletedEntry"Webhook 响应正文中仅存在未发布的条目 ID 和 a。所有其他字段值(例如path触发重新验证所需的值)均不可用。在这里,我们必须发出额外的请求来获取非活动者的帖子字段值。

Contentful 提供了Content Preview API,它允许您甚至从非活动条目中获取数据。

以下是使用 ID 以外的自定义路径值时 Webhook API 端点的伪代码:

// /pages/api/revalidate-post.js

export async function handler(req, res) {
    try {
        const reqBody = JSON.parse(req.body);
        await res.revalidate(`/post/${reqBody.sys.id}`); // revalidate post using entry id
        return res.json({ revalidated: true });
    } catch (err) {
        return res.status(500).send("Error revalidating");
    }
}
Run Code Online (Sandbox Code Playgroud)