在 Next.js SSR/ISR 中,回退 false 与 true 与阻塞 getStaticPaths(带或不带重新验证)之间有什么区别?

Cir*_*四事件 44 next.js

从 Next.js 10 开始,该getStaticPaths函数返回一个必须包含非常重要的fallback密钥的对象,如下所示: https: //nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required

虽然文档很精确,但对于刚开始使用 Next.js 的人来说很难理解,有人可以尝试提供这些选项的更简单或更具体的概述吗?

Cir*_*四事件 114

如何测试

首先,当进行测试以确保我理解它们时,我真的很困惑,因为当你在开发模式 ( next dev) 下运行时,其行为与在生产模式 ( ) 下运行时的行为完全不同next build && next start,因为它更加宽容帮助您快速发展。值得注意的是,在开发过程中,getStaticPaths每次渲染都会调用,因此所有内容总是渲染到最新版本,这与可能启用更多缓存的生产不同。

该文档描述了生产行为,因此要进行测试,您确实需要使用生产模式。

下一个问题是我无法轻松找到可以从示例本身内部创建和更新页面以轻松查看其行为的示例。我最终在https://github.com/cirosantilli/node-express-sequelize-nextjs-realworld-example-app上做到了这一点,同时移植了很棒的Realworld 示例项目,该项目生成了一个简单的多用户博客网站(迷你中型克隆) )。

有了这些工具,我就能够确认文档所说的内容。这个答案在这个具有 Next.js 10.2.2 的提交中进行了测试。

fallback: false

这很简单:只有在 期间生成的页面next build(即从paths属性返回的页面getStaticPaths)才是可见的。

例如,如果用户在 处创建了一个新的博客页面/post/[post-id],之后该页面不会立即可见,并且访问该 URL 将导致 404。

仅当您重新运行next buildgetStaticPaths返回该页面时,该新帖子才会变得可见,这是返回所有可能的paths典型用例的情况。getStaticPaths[post-id]

fallback: true

使用此选项,Next 检查页面是否已在 下预呈现为 HTML .next/server/pages

如果还没有:

  1. 接下来首先快速返回一个虚拟预渲染,其中包含在构建时创建的空数据。

    在此,您应该告诉用户页面正在加载。

    您必须处理这种情况,否则可能会导致由于缺少属性而引发异常。

    文档中通过检查描述了处理此问题的方法router.isFallback

    import { useRouter } from 'next/router'
    
    function Post({ post }) {
        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>
        }
    
        // Render post...
        return <div>{post.body}</div>
    
    }
    
    Run Code Online (Sandbox Code Playgroud)

    所以在这个例子中,如果我们没有做检查router.isFallback, post 将会是{},并且执行post.body会抛出异常

  2. 当实际页面第一次完成数据渲染后(数据getStaticProps在运行时获取),用户的浏览器会自动更新以查看它,并将生成的 HTML 存储在.next/server/pages

.next/server/pages但是,如果该页面出现在下面,则可能是因为:

  • 它是由next build
  • 它是在运行时第一次渲染的

Next.js 只是返回它,而不再次渲染。

因此,如果您编辑帖子,它不会重新渲染页面缓存。过时的页面将始终返回,因为它已经存在于 下.next/server/pages,因此 next 不会重新渲染它。

您必须重新运行next build才能看到页面的更新版本。

因此,这不是您通常想要的上述多用户博客。这种方法通常仅适用于没有用户生成内容的网站,例如您控制所有内容的电子商务网站。

fallback: true: 不存在的页面怎么办?

如果用户访问一个不存在的页面(例如 )/post/i-dont-exist,Next.js 将尝试像任何其他页面一样渲染它,因为它会检查它是否不存在,并认为.next/server/pages它之前尚未渲染过。

这与 Next.js 不同fallback: false,Next.js 在运行时从不生成新页面,而只是返回 404 方向。

在这种情况下,您的代码在查询数据库时会注意到该页面不存在getStaticProps,然后您告诉 Next.js 这是一个 404,notFound: true如:How to return a 404 Not Found page and HTTP status when a invalid Next.js 中传递动态路由的参数?因此 Next.js 呈现 404 页面并且不缓存任何内容。

fallback: 'blocking'

这与 非常相似fallback: true,只是当第一次访问未缓存的页面时,它不会返回虚拟加载页面

相反,它只会使浏览器挂起,直到第一次呈现页面。

然而,对该页面的未来请求很快就会从缓存中得到满足,就像fallback: true.

https://dev.to/tomdohnal/blocking-fallback-for-getstaticpaths-new-next-js-10-feature-1727提到了这样做的理由,它似乎破坏了某些相当具体的功能,并且通常不是您想要的除非您需要这些特定功能之一。

请注意,Next.js 文档明确指出fallback: true,它会检测爬虫(TODO 究竟如何?用户代理还是其他什么?哪个用户代理),并且不会将加载页面返回给爬虫,这将违背 SSR 的目的。https://nextjs.org/docs/basic-features/data-fetching#the-fallback-key-required提到:

注意:此“后备”版本不会为 Google 等爬虫提供服务,而是会以阻止模式呈现路径。

'blocking'因此,对于 SEO 目的来说,使用over似乎并没有巨大的优势true

但是,如果您的用户是安全狂并且禁用了 JavaScript,他们只会看到加载页面。您确定 Wayback 机器不会显示加载页面吗?关于什么wget?因为我喜欢这样的用例,所以我很想fallback: 'blocking'在任何地方使用。

revalidate:增量静态再生(ISR)

revalidate给定时,对缓存中页面的新请求.next/server/pages也会使缓存重新生成。这称为“增量静态再生”。

revalidate: n意味着我们的服务器每秒最多重新渲染 1 次n。如果在几秒之前收到第二个请求n,则返回先前渲染的页面并且不会触发新的重新渲染。如此大n意味着用户会看到更多过时的页面,但服务器工作负载更少。

因此,大量重新验证可以通过缓存回复来帮助服务器处理大流量峰值。

如果我们希望网站用户发布和更新自己的帖子,我们必须使用以下内容:

  • 两者fallback: true任一fallback: 'blocking'
  • 和...一起revalidate: <integer>

revalidate没有多大意义fallback: false

revalidate: <number>给出时,行为如下:

  • 如果页面存在于 下.next/server/pages,则立即返回此预呈现的内容,可能使用过时的数据呈现。

    同时,还使用最新数据启动页面重建。

    重建完成后,目标页面不会自动更新到最新版本。用户必须刷新页面才能看到更新的版本。

  • 否则,如果页面未缓存,则执行相同的操作true'blocking'将执行的操作,方法是返回虚拟等待页面,或阻塞直到完成,然后创建缓存页面

通过上述任一情况(无论是否第一次)构建页面后,如果下一秒再次访问该页面number,则不会触发重建。这样,如果有大量用户访问该网站,大多数请求将不需要昂贵的服务器渲染工作:我们每秒最多执行一次重新渲染number

显式失效:res.unstable_revalidate

目前这是测试版,但似乎最后他们引入了一种显式使页面无效的方法,如当前提到的: https: //vercel.com/docs/concepts/next.js/incremental-static-regenesis

这样,如果revalidate我们能够检测到页面在服务器上过时,我们将能够仅在需要时重建页面,而不是丑陋的超时。那么我们每次都可以直接切断。

res.revalidate一旦稳定,它可能会被重命名为。

塞巴斯蒂安在评论中引起了我对这一令人惊叹的发展的关注。

用于单个请求(即忽略revalidate)的 SSR,以便用户可以看到其博客页面编辑的结果

编辑:这个用例可能最好通过即将推出的res.unstable_revalidate/来解决res.revalidate

如果例如:

  • 博客作者在更新现有帖子后单击“提交”
  • 他们像往常一样被重定向到帖子查看页面,看看一切是否正常

他们首先看到该帖子的过时版本。然后重定向此访问将触发使用他们在编辑页面中提供的新数据进行重建,并且只有在完成并且用户刷新之后他们才会看到更新的页面。

因此,对于编辑器来说,这种行为也不是理想的 UI 行为,因为用户会思考:

刚刚发生了什么,我的编辑没有注册吗?

几秒钟。

这可以通过“预览模式”来解决,该模式记录在: https: //nextjs.org/docs/advanced-features/preview-mode它是在 Next.js 12 中添加的。预览模式检查是否设置了 cookies,并且如果是这样,则getStaticProps无论是否重新运行revalidate,就像getServerSideProps.

然而,即使预览模式也不能很好地解决这个用例,因为它不会使缓存失效/更新,这是一个广泛要求的事情,相关:

因此,用户仍然可能访问没有缓存的页面并看到过时的页面。我可以通过删除 cookie 并发出额外的 GET 请求来解决此问题,但这会产生无用的 get 请求并增加更多复杂性。

我在打开一个有关它的问题后了解到这一点: https: //github.com/vercel/next.js/discussions/25677感谢@sergioengineer指出了这一点。

相关主题:

SSR 与 ISR:基于每个用户登录的信息

ISR 是对 SSR 的优化。然而,就像每一个优化一样,它会增加系统的复杂性。

例如,假设用户可以“收藏”博客文章。

如果我们使用 ISR,那么只有预渲染注销页面才有意义,因为只有预渲染多个用户共用的内容才有意义。

因此,如果我们想向用户展示信息:

我是否已为此页面加注星标?

然后我们必须执行第二个 API 请求,然后用它更新页面状态。

虽然听起来很简单,但根据我的经验,这给代码增加了相当大的额外复杂性。

然而,使用 SSR,我们可以像往常一样简单地检查用户发送的登录 cookie,并在服务器上完全呈现针对当前用户完美定制的页面,从而不需要进一步的 API 请求。简单多了。

因此,只有当你对它进行基准测试并且值得时,你才应该这样做。

以下是检查登录 cookie 的示例:https://github.com/cirosantilli/node-express-sequelize-nextjs-realworld-example-app/blob/8dff36e4bcf659fd048e13f246d50c776fff0028/back/IndexPage.ts#L23该示例设置使用完全相同的内容SWR 令牌用于发出 JavaScript API 请求,但也可通过 cookie 进行请求。我们不必担心该演示中的 XSS,因为我们只在 GET 请求上使用登录。所有修改请求(例如 POST)均仅通过 JavaScript 完成,并且不通过 cookie 进行身份验证。

ISR 梦想:无限revalidate+ 显式失效 + CDN 挂钩

从 Next.js 12 开始,ISR 对于这样一个 CRUD 网站来说是不稳定的,我真正想要的是事情按如下方式工作:

  • 当用户创建博客文章时,我们使用帖子创建挂钩将结果上传到选择的 CDN
  • 当用户查看博客文章时,直接访问 CDN,不接触服务器。仅当用户想要获取特定于用户的数据(例如“我是否已为此页面加注星标”)时,它才会向服务器发出小型 API 请求
  • 当用户更新博客文章时,它只会更新所选 CDN 上的结果

这种方法确实会带来超快的页面加载和最小的服务器工作负载涅槃。

我认为 Next.js 背后的公司 Vercel 可能会在他们的产品上运行这样的 CDN 系统,但我不知道如何很好地使用任意选择的 CDN,因为我没有看到这样的钩子。我希望我错了:-)

但即使没有 CDN 挂钩系统,仅显式失效 + 无限重新验证就已经是一件很棒的事情了。编辑:这可能会随 一起出现res.unstable_revalidate,请参阅上面的部分。

  • 感谢您的见解。我不知道“阻塞”存在的一个主要理由是搜索引擎不缓存“加载”状态。 (2认同)

Moe*_*nia 11

每当我们想要在 中实现ISRSSG技术时dynamic routes,我们都应该传递我们希望在构建时静态生成的路径来getStaticPaths运行。尽管,在某些情况下,我们可能有未返回的新路径getStaticPaths,并且我们有使用后备属性来处理此路径,该属性也从getStaticPathsNext.js 官方文档返回 。

f allback 属性可以接受 3 个值:

  1. false : 新路径将导致 404 页面

  2. true : 新路径将静态生成(getStaticProps被调用)- 生成页面时显示加载状态router.isFallback(通过并显示后备页面)-生成后使用所需的道具渲染页面-新路径将缓存在 CDN 中(稍后的请求将导致缓存页面)-爬虫机器人可能会索引后备页面(不利于 Seo)

  3. “blocking” : 新路径将等待生成 HTML(通过SSR- 不会有加载状态(没有后备页面) -新路径将缓存在 CDN 中(稍后的请求将导致缓存页面)

注意:在 Next.js 12 之后,fallback:trueinISR技术不会向爬虫机器人显示后备页面 阅读更多


归档时间:

查看次数:

28739 次

最近记录:

3 年,5 月 前