⚠️
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,可能会遇到一个导致重新验证值不一致的 bug。问题在于它使用页面中所有 fetch 调用中最低的重新验证值进行重新验证,而不考虑它们各自的值。要修复此 bug,您需要使用以下代码片段修改根布局组件中的 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 <>...</>;
}