reactjs NEXT.js ISR删除静态页面

6uxekuva  于 2023-03-12  发布在  React
关注(0)|答案(1)|浏览(173)

ISR出现了一点问题。我的revalidate prop等于1,如下所示

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,
    },
  };
}

当我在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,
 };
}

产品页面

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>
  );
};

***编辑***重新验证后,在Contentful中将产品名称从“product77”更改为“product7”时,product77构建版本中的静态页面仍然存在,我仍然可以进入该页面。

再确认后不应该删除吗?

xuo3flqw

xuo3flqw1#

被移除的页面不能被删除,但会以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
    };
}

以上代码的主要启示是:

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

按需重新验证需要一个附加文件,即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");
    }
}

res.revalidate(``/${reqBody.path}``)使用getStaticProps中的逻辑调用页面的新求值。
现在,如果有人删除CMS中的页面,并为删除的页面路径触发上面的重新验证webhook处理程序,那么该路径将服务于404页面而不是原始页面。
但是,页面本身不会从磁盘中删除。

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

在Contentful中,在“Unpublish”webhook通知期间,webhook响应正文中只显示未发布的条目ID和type: "DeletedEntry"。所有其他字段值(例如,触发重新验证所需的path)都不可用。在这里,我们必须进行额外请求以获取非活动的发布字段值。
Contentful提供了Content Preview API,它允许您甚至从非活动条目中获取数据。
以下是使用自定义路径值而不是ID时webhook API端点的伪代码:

export async function handler(req, res) {
    try {
        const reqBody = JSON.parse(req.body);

        let pageToRevalidate = "";
        if (reqBody.sys.type === "DeletedEntry") {
            /**
             * "Unpublished" (type = DeletedEntry) status entries in
             * Contentful are not available on the normal API endpoints. Here, we
             * have to make an additional API request to the Preview API service,
             * asking for data for the entry with id reqBody.sys.id.
             */
            const unpublishedRes = await fetch(
                `https://previewAPI.../posts/${context.params.post}`
            );
            const unpublishedData = await unpublishedRes.json();
            pageToRevalidate = `/${unpublishedData.fields.slug}`;
        } else {
            pageToRevalidate = `/${reqBody.fields.slug}`;
        }
        await res.revalidate(pageToRevalidate);
        return res.json({ revalidated: true });
    } catch (err) {
        return res.status(500).send("Error revalidating");
    }
}

相关问题