import { NextRequest, NextResponse } from "next/server"; import { draftMode, cookies } from "next/headers"; import { fetchPreviewPage, resolvePreviewPath, PREVIEW_CONTENT_TYPE_COOKIE, PREVIEW_TOKEN_COOKIE, } from "@/services/preview.service"; import type { WagtailPageSummary } from "@/types/wagtail"; /** * Wagtail 编辑器点击"预览"后会重定向到此路由(详见 wagtailcms/settings/base.py * 中 WAGTAIL_HEADLESS_PREVIEW.CLIENT_URLS)。校验 token 有效后开启 Next.js * Draft Mode 并重定向到对应内容的前端路由,由页面组件通过 getPreviewOrFallback * 拉取草稿数据渲染。 */ export async function GET(request: NextRequest) { const contentType = request.nextUrl.searchParams.get("content_type"); const token = request.nextUrl.searchParams.get("token"); if (!contentType || !token) { return NextResponse.json( { error: "缺少 content_type 或 token 参数" }, { status: 400 }, ); } // 先校验 token 是否有效并取回 slug,未开启 Draft Mode,避免暴露无效预览。 const page = await fetchPreviewPage(contentType, token); const path = page ? resolvePreviewPath(contentType, page) : null; if (!page || !path) { return NextResponse.json( { error: "预览链接无效或已过期" }, { status: 404 }, ); } const draft = await draftMode(); draft.enable(); const isProduction = process.env.NODE_ENV === "production"; const cookieStore = await cookies(); const cookieOptions = { httpOnly: true, sameSite: "lax" as const, secure: isProduction, path: "/", }; cookieStore.set(PREVIEW_CONTENT_TYPE_COOKIE, contentType, cookieOptions); cookieStore.set(PREVIEW_TOKEN_COOKIE, token, cookieOptions); return NextResponse.redirect(new URL(path, request.url)); }