⚠️
next/cache
的重新验证功能需要 next@13.5.1
或更高版本才能正常工作。如果您使用的是旧版本,
请进行升级。
按需重新验证
当你手动为特定页面重新验证 Next.js 缓存时,存储在 S3 上的 ISR 缓存文件将会更新。然而,仍需要使 CloudFront 缓存失效:
// pages/api/revalidate.js
export default async function handler(req, res) {
await res.revalidate("/foo");
await invalidateCloudFrontPaths(["/foo"]);
// ...
}
如果使用的是 pages 路由,还必须使 _next/data/BUILD_ID/foo.json
路径失效。BUILD_ID
的值可以在 .next/BUILD_ID
构建输出中找到,并且可以通过 process.env.NEXT_BUILD_ID
环境变量在运行时访问。
await invalidateCloudFrontPaths(["/foo", `/_next/data/${process.env.NEXT_BUILD_ID}/foo.json`]);
以下是 invalidateCloudFrontPaths()
函数的示例:
import { CloudFrontClient, CreateInvalidationCommand } from "@aws-sdk/client-cloudfront";
const cloudFront = new CloudFrontClient({});
async function invalidateCloudFrontPaths(paths: string[]) {
await cloudFront.send(
new CreateInvalidationCommand({
// 在此处设置 CloudFront 分配 ID
DistributionId: distributionId,
InvalidationBatch: {
CallerReference: `${Date.now()}`,
Paths: {
Quantity: paths.length,
Items: paths,
},
},
})
);
}
请注意,手动使 CloudFront 路径失效会产生费用。根据 AWS CloudFront 定价页面 (opens in a new tab):
每月前 1,000 条路径的失效请求不收取额外费用。此后,每条路径的失效请求收费 $0.005。
由于这些费用,如果需要使多个路径失效,使用通配符路径 /*
会更经济。例如:
// 在前 1000 条路径之后,这将花费 $0.005 x 3 = $0.015
await invalidateCloudFrontPaths(["/page/a", "/page/b", "/page/c"]);
// 这将花费 $0.005,但也会使其他路由如 "page/d" 失效
await invalidateCloudFrontPaths(["/page/*"]);
对于通过 next/cache
模块 (opens in a new tab)进行的按需重新验证,如果你想获取与给定标签关联的路径,可以使用以下函数:
function getByTag(tag: string) {
try {
const { Items } = await this.dynamoClient.send(
new QueryCommand({
TableName: process.env.CACHE_DYNAMO_TABLE,
KeyConditionExpression: "#tag = :tag",
ExpressionAttributeNames: {
"#tag": "tag",
},
ExpressionAttributeValues: {
":tag": { S: `${process.env.NEXT_BUILD_ID}/${tag}` },
},
})
);
return (
// 我们需要从路径中移除 buildId
Items?.map(({ path: { S: key } }) => key?.replace(`${process.env.NEXT_BUILD_ID}/`, "") ?? "") ?? []
);
} catch (e) {
error("Failed to get by tag", e);
return [];
}
}
针对 ISR 的 fetch 行为补丁(仅适用于 next@13.5.1+ 版本)
如果您在应用中使用 ISR(增量静态再生)和 fetch,可能会遇到一个导致 revalidate 值不一致的 bug。该问题的表现是:页面会使用所有 fetch 调用中最小的 revalidate 值进行再生,而忽略它们各自的设置值。要修复此问题,您需要在根布局组件中通过以下代码片段修改 fetch 函数:
export default function RootLayout() {
const asyncStorage = require("next/dist/client/components/static-generation-async-storage.external");
//@ts-ignore
const staticStore = (fetch as any).__nextGetStaticStore?.() || asyncStorage.staticGenerationAsyncStorage;
const store = staticStore.getStore();
store.isOnDemandRevalidate = store.isOnDemandRevalidate && !(process.env.OPEN_NEXT_ISR === 'true');
return <>...</>;
}