增加按需ISR增量静态更新功能
This commit is contained in:
parent
a15a7e0c18
commit
58e1794c9f
@ -12,13 +12,20 @@ const LoadingSpinner = () => (
|
||||
</div>
|
||||
);
|
||||
|
||||
export const revalidate = Number(process.env.JSITE_REVALIDATE_SECONDS) || 3600;
|
||||
// Using a static value to comply with Next.js 15 build requirements.
|
||||
// On-demand revalidation will be handled via the API route.
|
||||
export const revalidate = 3600;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const slugs = await getAllSlugs();
|
||||
return slugs.map(slug => ({
|
||||
slug: slug,
|
||||
}));
|
||||
try {
|
||||
const slugs = await getAllSlugs();
|
||||
return slugs.map(slug => ({
|
||||
slug: slug,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Failed to generate static params:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }) {
|
||||
|
||||
55
app/api/revalidate/route.js
Normal file
55
app/api/revalidate/route.js
Normal file
@ -0,0 +1,55 @@
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
|
||||
/**
|
||||
* 按需重新验证 API 路由
|
||||
* 当后端内容更新时,通过调用此 API 来手动触发特定页面的重新生成。
|
||||
*
|
||||
* 调用方式:
|
||||
* POST /api/revalidate
|
||||
* Headers:
|
||||
* Content-Type: application/json
|
||||
* x-revalidate-secret: YOUR_SECRET_TOKEN
|
||||
* Body:
|
||||
* {
|
||||
* "path": "/page-to-revalidate"
|
||||
* }
|
||||
*/
|
||||
export async function POST(request) {
|
||||
|
||||
// 1. 从请求头中获取密钥
|
||||
const secret = request.headers.get('x-revalidate-secret');
|
||||
|
||||
// 2. 验证密钥
|
||||
// 为了安全,这个密钥应该存储在环境变量中,并且不能硬编码。
|
||||
if (secret !== process.env.REVALIDATE_TOKEN) {
|
||||
console.warn('Invalid revalidate token received.');
|
||||
return NextResponse.json({ message: 'Invalid token' }, { status: 401 });
|
||||
}
|
||||
|
||||
// 3. 从请求体中获取并记录需要重新验证的路径
|
||||
const body = await request.json();
|
||||
const { path } = body;
|
||||
|
||||
console.log('Revalidation request body:', body);
|
||||
|
||||
if (!path) {
|
||||
console.warn('Revalidation request received without a path.');
|
||||
return NextResponse.json({ message: 'Path is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
// 4. 调用 Next.js 的 revalidatePath 函数
|
||||
// 这将清除指定路径的缓存,并在下次请求时重新生成页面。
|
||||
revalidatePath(path);
|
||||
console.log(`Successfully revalidated path: ${path}`);
|
||||
return NextResponse.json({ revalidated: true, now: Date.now() });
|
||||
} catch (error) {
|
||||
// 5. 如果发生错误,返回错误信息
|
||||
console.error(`Error revalidating path: ${path}`, error);
|
||||
return NextResponse.json(
|
||||
{ message: 'Error revalidating', error: error.message },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -4,7 +4,9 @@ import CategoryItems from "@/components/homes/home-15/CategoryItems";
|
||||
import React from "react";
|
||||
import { getSiteSettings } from "@/utils/siteSettings";
|
||||
|
||||
export const revalidate = Number(process.env.JSITE_REVALIDATE_SECONDS) || 3600;
|
||||
// Using a static value to comply with Next.js 15 build requirements.
|
||||
// On-demand revalidation will be handled via the API route.
|
||||
export const revalidate = 3600;
|
||||
|
||||
export async function generateMetadata() {
|
||||
const siteUrl = process.env.SITE_URL;
|
||||
|
||||
@ -4,6 +4,7 @@ import { getSiteSettings } from "@/utils/siteSettings";
|
||||
import { notFound } from 'next/navigation';
|
||||
import DynamicListPage from "@/components/common/DynamicListPage";
|
||||
import { Suspense } from 'react';
|
||||
import { getPageData } from "@/utils/data";
|
||||
|
||||
const baseSlug = 'products';
|
||||
|
||||
@ -19,13 +20,8 @@ export async function generateMetadata({ params }) {
|
||||
const resolvedParams = await params;
|
||||
const slug = resolvedParams.slug || [];
|
||||
const slugArr = [baseSlug, ...(Array.isArray(slug) ? slug : [slug])];
|
||||
const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ slug_list: slugArr })
|
||||
});
|
||||
const json = await res.json();
|
||||
const { data, error, page_info } = json;
|
||||
const { data, error, page_info } = await getPageData({ slug_list: slugArr });
|
||||
|
||||
if (error) {
|
||||
return {
|
||||
title: error.title || 'Page Error',
|
||||
@ -52,14 +48,13 @@ export default async function Page({ params }) {
|
||||
const siteSettings = await getSiteSettings(process.env.SITE_URL);
|
||||
const pageSize = Number(siteSettings.page_size) || 12;
|
||||
|
||||
// Fetch only page 1 for initial static render
|
||||
const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ slug_list: slugArr, page: 1, page_size: pageSize })
|
||||
const { data, error, total } = await getPageData({
|
||||
slug_list: slugArr,
|
||||
page: 1,
|
||||
page_size: pageSize,
|
||||
downloadFiles: true,
|
||||
});
|
||||
const result = await res.json();
|
||||
const { data, error, total } = result;
|
||||
|
||||
if (error) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ export default function SwiperItemsUI({ data, items, ...props }) {
|
||||
const subtitle = data?.subtitle || props.subtitle;
|
||||
const category_slug = data?.t3 || props.category_slug || "";
|
||||
const columns = data?.t5 || props.columns || 4;
|
||||
const button_text = data?.button_text || props.button_text || "查看详情";
|
||||
const rows = (data?.p1 && !isNaN(Number(data.p1))) ? Number(data.p1) : (props.rows || 1);
|
||||
|
||||
// Loading and error states are now handled by the server component and React Suspense.
|
||||
@ -190,7 +191,7 @@ export default function SwiperItemsUI({ data, items, ...props }) {
|
||||
<span className="bg"></span>
|
||||
<figcaption className="group-hover:opacity-100 absolute w-full h-full opacity-0 text-center px-4 py-3 inset-0 z-[5] pointer-events-none p-2">
|
||||
<h5 className="from-top !mb-0 absolute w-full translate-y-[-80%] p-[.75rem_1rem] left-0 top-2/4">
|
||||
查看详情
|
||||
{button_text}
|
||||
</h5>
|
||||
</figcaption>
|
||||
</Link>
|
||||
|
||||
BIN
public/files/1732346059482090.jpg
Normal file
BIN
public/files/1732346059482090.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
public/files/1732346059493375.jpg
Normal file
BIN
public/files/1732346059493375.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
public/files/1732346060256137.jpg
Normal file
BIN
public/files/1732346060256137.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
BIN
public/files/1732346060269459.jpg
Normal file
BIN
public/files/1732346060269459.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 83 KiB |
Loading…
x
Reference in New Issue
Block a user