> For the complete documentation index, see [llms.txt](https://onenesss-organization.gitbook.io/jj-xiaoce/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://onenesss-organization.gitbook.io/jj-xiaoce/next.js-kai-fa-zhi-nan/20.-pei-zhi-pian-lu-you-duan-pei-zhi-xiang.md).

# 20. 配置篇 ❘ 路由段配置项

### 前言

之前的文章中已经多次提到了路由段配置项，路由段配置选项可以配置页面、布局、路由处理程序的行为，本篇我们会详细介绍其中的配置内容。

### 1. 段（Segment）

如果大家翻阅 Next.js 的官方文档（英文），会经常发现 Segment 这个单词，其释义为：

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1795b49110b1459081bb3672aeb4bd31~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=992\&h=848\&s=193982\&e=png\&b=1c1e20)

为了简单起见，我翻译成“段”。Segment 放到 URL 这个场景时：

**URL Segment** 指的是由斜杠分隔的 URL Path 的一部分 **URL Path** 指的则是域名后面的 URL 部分（URL Path 由 URL Segment 组成）

用这张图表示更清晰一些：

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b20bb421ef334b9699bc7773c6f67fa7~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1600\&h=371\&s=223859\&e=png\&b=131313)

Segment 放到 Route 这个场景时：

**Router Segment**，我翻译为“路由段”，路由中的每个文件夹都代表一个路由段。每个路由段都映射一个对应的 URL Segment：

![image.png](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/83ecaf2828ef4e668a4146812ff7c9f3~tplv-k3u1fbpfcp-jj-mark:0:0:0:0:q75.image#?w=1600\&h=594\&s=339521\&e=png\&b=141414)

在这张图中，`/dashboard/settings`由三段组成：

* `/`：根段（Root Segment）
* `dashboard`：段（Segment）
* `settings`：叶段（Leaf Segment）

PS：叶段指的是没有子节点的段。

### 2. 路由段配置（Route Segment Config）

接下来我们来到本章的正题——路由段配置。

路由段配置选项可以配置页面、布局、路由处理程序的行为。比如我们使用 fetch 的时候可以单独配置某个请求的 `revalidate` ，借助路由段配置，我们可以配置这个路由下所有 fetch 请求的 `revalidate`。

路由段配置的使用方式也很简单，导出一个约定变量名即可，比如：

```javascript
// layout.js | page.js | route.js
export const dynamic = 'auto'
export const dynamicParams = true
export const revalidate = false
export const fetchCache = 'auto'
export const runtime = 'nodejs'
export const preferredRegion = 'auto'
export const maxDuration = 5
 
export default function MyComponent() {}
```

具体这些变量名和值的类型为：

| **变量名**                                                                                                            | **类型**                                                                                                                    | **默认值**    |
| ------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ---------- |
| [dynamic](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamic)                 | `'auto' \| 'force-dynamic' \| 'error' \| 'force-static'`                                                                  | `'auto'`   |
| [dynamicParams](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#dynamicparams)     | `boolean`                                                                                                                 | `true`     |
| [revalidate](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#revalidate)           | `false \| 'force-cache' \| 0 \| number`                                                                                   | `false`    |
| [fetchCache](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#fetchcache)           | `'auto' \| 'default-cache' \| 'only-cache' \| 'force-cache' \| 'force-no-store' \| 'default-no-store' \| 'only-no-store'` | `'auto'`   |
| [runtime](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#runtime)                 | `'nodejs' \| 'edge'`                                                                                                      | `'nodejs'` |
| [preferredRegion](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#preferredregion) | `'auto' \| 'global' \| 'home' \| string \| string[]`                                                                      | `'auto'`   |
| [maxDuration](https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#maxduration)         | `number`                                                                                                                  | 部署平台设置     |

注意配置选项的值目前是静态分析的，也就是说，配置`revalidate = 600`是有效的，但是 `revalidate = 60 * 10`是无效的。

我们来一一讲解这些配置选项的作用。

#### 2.1. dynamic

更改布局或者页面的动态行为，用例如下：

```javascript
// layout.js | page.js | route.js
export const dynamic = 'auto'
// 'auto' | 'force-dynamic' | 'error' | 'force-static'
```

为了讲解 dynamic 参数的选项，我们先复习下基础知识：

所谓**静态渲染（Static Rendering）**，指的是路由在构建时渲染，或者在重新验证后后台渲染，其结果会被缓存并可以推送到 CDN。适用于未针对用户个性化且数据已知的情况，比如静态博客文章、产品介绍页面等。

所谓**动态渲染（Dynamic Rendering）**，指的是路由在请求时渲染，适用于针对用户个性化或依赖请求中的信息（如 cookie、URL 参数）的情况。

因为渲染模式和数据缓存是相互独立的，所以在动态渲染下，数据请求也分为缓存和不缓存（[uncached data request](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching)）的。默认是缓存，这样做的好处在于，即便选择了动态渲染，也不用担心渲染时获取所有数据对性能造成影响。

`dynamic` 影响的不仅是渲染模式，也会影响数据缓存的方式。

还有一个名词叫**动态函数（Dynamic Functions）**，指的是获取只能在请求时才能得到的信息（如 cookie、请求头、URL 参数）的函数，在 Next.js 中，对应的就是 `cookies()`、`headers()`、`useSearchParams()`、`searchParams()` 这些函数。如果使用了这些函数的任意一个，都会导致路由进行动态渲染。

接下来我们讲解 `dynamic` 的值都有哪些作用：

* `'auto'`（默认）：自动判断
* `'force-dynamic'`，强制动态渲染和退出所有 fetch 请求缓存，相当于：
  * Page Router 下使用了 `getServerSideProps()`
  * 将布局或页面中每个 `fetch()` 请求都设置为 `{ cache: 'no-store', next: { revalidate: 0 } }`
  * 设置了路由段配置 `export const fetchCache = 'force-no-store'`
* `'error'`强制静态渲染并缓存数据，如果有组件使用了动态函数或不缓存数据请求（[uncached data request](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching)），就会导致错误，相当于：
  * Page Router 下使用了`getStaticProps()`
  * 将布局或页面中每个 `fetch()` 请求都设置为 `{ cache: 'force-cache' }`
  * 设置了路由段配置 `fetchCache = 'only-cache', dynamicParams = false`
  * 设置`dynamic = 'error'` 会更改 `dynamicParams` 的默认值 `true` 为 `false`
* `'force-static'` 强制静态渲染并缓存数据，强制 `cookies()`、`headers()`、`useSearchParams()` 返回空值。

#### 2.2. dynamicParams

控制当访问不是由 `generateStaticParams` 生成的动态路由段的时候发生什么。

```javascript
// layout.jsx | page.jsx
export const dynamicParams = true // true | false,
```

* `true`（默认）：按需生成
* false：返回 404

这个选项对应 Page Router 下的 `getStaticPaths` 的 `fallback: true | false | blocking`选项。

如果使用了 `dynamic = 'error'` 和 `dynamic = 'force-static'`，它会更改 `dynamicParams` 的默认值为 `false`。

#### 2.3. revalidate

设置布局或者页面的默认验证时间。此设置不会覆盖单个 `fetch` 请求设置的 `revalidate` 的值。注意 `revalidate` 选项只能用于 Nodejs Runtime，不能用于 Edge Runtime。

```javascript
// layout.jsx | page.jsx | route.js
export const revalidate = false
// false | 'force-cache' | 0 | number
```

* `false`（默认），语义上相当于 `revalidate: Infinity`，资源无限期缓存。
* `0`，页面或布局总是动态渲染，即使没有使用动态函数或者不缓存数据请求（[uncached data request](https://nextjs.org/docs/app/building-your-application/data-fetching/fetching-caching-and-revalidating#opting-out-of-data-caching)）。
* `number` ：设置布局或页面的默认重新验证频率，以秒为单位。

关于重新验证频率，一个路由可能有多个布局和一个页面，此时会选择最低的 `revalidate` 值作为路由的重新验证频率。这是为了确保子路由的重新验证时间频率和父布局保持一致。此外，单个 fetch 请求可以设置比路由默认的 `revalidate` 值更低的 `revalidate` 值，这会增加整个路由的重新验证频率。这允许你根据某些动态条件进行更频繁的重新验证。

#### 2.4. fetchCache

这是一个高级选项，仅当你特别需要覆盖默认行为时才应该使用。为了解释这个选项，我们先复习下 fetch 请求的 `options.cache` 选项：

```javascript
fetch(`https://...`, { cache: 'force-cache' | 'no-store' })
```

其中 `force-cache`是默认值，表示优先从缓存中查找匹配请求，当没有匹配项或者匹配项过时时，才从服务器上获取资源并更新缓存。`no-store`表示每次请求都从服务器上获取资源，不从缓存中查，也不更新缓存。

回到 Next.js，默认情况下，Next.js 会缓存在动态函数使用之前的 `fetch` 请求，不会缓存任何动态函数之后的`fetch` 请求。而 `fetchCache` 允许你覆盖布局或者页面中所有的 `fetch`请求的默认 `cache`选项。

```javascript
// layout.jsx | page.jsx | route.js
export const fetchCache = 'auto'
// 'auto' | 'default-cache' | 'only-cache'
// 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'
```

* `'auto'`（默认）：动态函数之前按照开发者设置的 `cache` 选项进行缓存，动态函数之后不缓存请求
* `'default-cache'`：开发者可以自由设置 `cache` 选项，但如果开发者未设置 `cache` 选项，默认设置为 `force-cache`，这意味着即使是在动态函数之后的请求，也会被视为静态
* `'only-cache'`：如果开发者未设置 `cache` 选项，默认设置为 `force-cache`，如果有请求设置成 `cache: 'no-store'`，则会导致报错
* `'force-cache'`：将所有请求的 `cache` 选项设置为 `force-cache` 。
* `'default-no-store'`：开发者可以自由设置 `cache` 选项，但如果开发者未设置 `cache` 选项，默认设置为 `no-store`，这意味着即使是在动态函数之前的请求，也会被视为动态。
* `'only-no-store'`：如果开发者未设置 `cache` 选项，默认设置为 `no-store`，如果有请求设置成 `cache: 'force-cache'`，则会导致报错
* `'force-no-store'`：将所有请求的 `cache` 选项设置为 `no-store` 。

一个路由可能有多个布局和一个页面，此时选项应该相互兼容：

* 如何 `'only-cache'` 和 `'force-cache'` 同时提供，`'force-cache'` 获胜。如果 `'only-no-store'` 和 `'force-no-store'`同时提供，`'force-no-store'`获胜。带 `force` 的选项会更改整个路由的行为，并会阻止 `'only-*'` 引发的错误。
* `'only-*'` 和 `force-*'`选项的作用就是确保整个路由要么是完全静态要么是完全动态，这意味着：
  * 在单个路由中不允许同时使用 `'only-cache'`和 `'only-no-store'`
  * 在单个路由中不允许同时使用 `'force-cache'`和 `'force-no-store'`
* 如果子级提供了 `'auto'`或 `'*-cache'`，父级无法使用 `'default-no-store'`，因为这会导致请求有不同的行为。

Next.js 建议共享的父布局使用 `'auto'`，在子级中自定义不同的选项。

#### 2.5. runtime

设置运行时环境，具体参考小册[《渲染篇 | Streaming 和 Edge Runtime》](https://juejin.cn/book/7307859898316881957/section/7309076865732640818)

```javascript
// layout.jsx | page.jsx | route.js
export const runtime = 'nodejs'
// 'edge' | 'nodejs'
```

* `nodejs`（默认）
* `edge`

#### 2.6. preferredRegion

在 [Vercel Serverless Functions](https://vercel.com/docs/functions/serverless-functions) 中使用，搭配 `export const runtime = 'edge';` ，用于设置 [Edge Functions](https://vercel.com/docs/functions/configuring-functions/region) 执行的区域，默认情况下，Edge Functions 在最接近传入请求的区域中执行，但如果你的函数比较依赖数据源，你会更希望它靠近数据源所在的位置以实现快速响应，那就可以设置 preferredRegion 指定一系列首选区域。

指定区域的时候，传入的是区域 ID，区域列表参考 [Vercel 的 Region List 文档](https://vercel.com/docs/edge-network/regions)，其中 iad1 表示美国东部区域，参考位置美国华盛顿地区，sfo1 表示美国西部，参考位置美国旧金山。

```javascript
// layout.jsx | page.jsx | route.js
export const preferredRegion = 'auto'
// 'auto' | 'global' | 'home' | ['iad1', 'sfo1']
```

#### 2.7. maxDuration

在 [Vercel Serverless Functions](https://vercel.com/docs/functions/serverless-functions) 中使用，用于配置 [Vercel 函数](https://vercel.com/docs/functions/configuring-functions/duration)的最大持续时间，所谓 Max duration，指的是函数在响应之前可以处理 HTTP 请求的最长时间。如果持续时间内没有响应，则会返回错误码。如果没有指定，根据不同的部署平台，默认时间会不同。

```javascript
export const maxDuration = 5
```

#### 2.8 generateStaticParams

与动态路由搭配使用，用于定义静态生成的路由段参数。具体内容参考小册[《API 篇 | 路由相关的常用方法》](https://juejin.cn/book/7307859898316881957/section/7309079586296791050#heading-1)

### 参考链接

1. <https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config>
2. <https://vercel.com/docs/functions/configuring-functions/region>
