Next.js 与 Umbraco Delivery API 构建静态博客:无头 CMS 接入、静态生成与 Preview Mode 全链路实战 Next.js 与 Umbraco Delivery API 构建静态博客无头 CMS 接入、静态生成与 Preview Mode 全链路实战【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js本文以 Next.js 官方仓库中的examples/cms-umbraco示例为主体完整讲解如何用 Umbraco 的 Content Delivery API 作为无头数据源、用 Next.js 的 Static Generation 特性生成博客站点并实现 Preview Mode 草稿预览。读完本文你将掌握从 Umbraco .NET 后端搭建、Delivery API 启用、环境变量配置到前端静态数据抓取getStaticPaths/getStaticProps与预览模式 Cookie 机制的完整落地方案。示例概览该示例是一个静态生成的博客A statically generated blog example using Next.js and Umbraco CMS核心特征是数据源Umbraco CMS 原生的Content Delivery APIHeadless 内容交付 APINext.js 在构建/请求时通过 HTTP 拉取内容渲染方式基于 Next.js 的 Static Generation文章列表与详情页均为构建时/请求时预渲染的静态 HTML预览能力通过 Next.js 的Preview ModeDraft Mode配合 Delivery API 的Preview请求头查看尚未发布的 Umbraco 内容变更技术栈React 18 TypeScript Tailwind CSS见 package.jsonnext、react 18、tailwindcss 3。仓库内还有 Umbraco heartcore 等同类示例本文只聚焦本示例。快速开始脚手架初始化使用create-next-app拉取本示例npm / Yarn / pnpm 三种方式npx create-next-app --example cms-umbraco umbraco-appyarn create next-app --example cms-umbraco umbraco-apppnpm create next-app --example cms-umbraco umbraco-app执行后会在umbraco-app目录下生成完整的 Next.js 博客工程示例目录结构与主要文件对应关系如下以仓库内目录为准目录/文件作用lib/api.ts所有 Delivery API 请求与数据抽取逻辑pages/index.tsx首页getStaticProps拉取文章列表pages/posts/[slug].tsx文章详情页getStaticPathsgetStaticPropspages/api/preview.ts开启 Preview Mode 的 API 路由pages/api/exit-preview.ts退出 Preview Mode 的 API 路由next.config.js将 Umbraco 域名加入next/image白名单.env.local.example环境变量模板types/post.ts文章的数据模型构建数据源Umbraco 后端Step 15博客数据来自本地运行的 Umbraco 站点需要先把它搭起来。以下是原文档给出的完整步骤。Step 1. 创建 Umbraco 项目使用 .NET CLI 在本地创建项目创建一个空文件夹并在其中打开终端安装 Umbraco .NET CLI 模板要求 12.0 及以上版本dotnet new install Umbraco.Templates::13.*创建 Umbraco 项目dotnet new umbracoStep 2. 安装示例数据为避免手工创建整套博客数据集官方提供了名为Umbraco.Sample.Headless.Blog的 NuGet 包在 Umbraco 项目的终端中安装dotnet add package Umbraco.Sample.Headless.BlogStep 3. 启用 Delivery APIUmbraco Delivery API 是博客的数据源必须显式启用。打开 Umbraco 项目中的appsettings.json在Umbraco::CMS节点内添加DeliveryApi配置Umbraco: { CMS: { DeliveryApi: { Enabled: true, ApiKey: my-secret-api-key }, ... } }其中ApiKey是可选配置——只有需要测试博客的 Preview草稿预览功能时才是必需的后续 Next.js 端会通过请求头Api-Key带上这个密钥。Step 4. 运行 Umbraco在 Umbraco 项目终端中启动dotnet run按安装向导完成 Umbraco 初始化完成后会跳转到 Umbraco backoffice后台此时示例数据已经安装好。Step 5. 发布示例数据示例内容初始状态全部未发布必须发布后博客才会显示文章在 Content 树中点击Posts节点它包含所有文章在浏览器窗口右下角找到绿色的 Save and publish 按钮点击按钮旁的小上箭头选择 Publish with descendants...在对话框中勾选 Include unpublished content items一次性发布Posts及其下所有文章。对Authors节点重复同样操作。配置 Next.js 端环境变量Step 6在umbraco-app目录下找到.env.local.example复制一份命名为.env.local并填写。仓库中的模板文件.env.local.example内容为# This is necessary when you run locally against a self-signed server. Do NOT include this in production. NODE_TLS_REJECT_UNAUTHORIZED0 # Add your Umbraco server URL here. Please do not include a trailing slash. UMBRACO_SERVER_URL # Add your Umbraco Delivery API key here if you want to use preview. UMBRACO_DELIVERY_API_KEY # Add the secret token that will be used to authorize preview UMBRACO_PREVIEW_SECRET 三个核心变量的含义UMBRACO_SERVER_URLUmbraco 站点的基础 URL不要带尾部斜杠UMBRACO_DELIVERY_API_KEY即 Step 3 中在appsettings.json里配置的 API key仅测试 Preview Mode 时需要UMBRACO_PREVIEW_SECRET任意随机字符串避免空格如my-preview-secret用于授权触发预览仅 Preview Mode 需要。填写完成后大致形如NODE_TLS_REJECT_UNAUTHORIZED0 UMBRACO_SERVER_URL https://localhost:12345 UMBRACO_DELIVERY_API_KEY my-secret-api-key UMBRACO_PREVIEW_SECRET my-preview-secret关于NODE_TLS_REJECT_UNAUTHORIZED0本地运行 .NET 站点时会自动创建自签名 SSL 证书以支持 HTTPS 绑定而 Node.js 默认不信任自签证书因此需要这个开关绕过 TLS 证书校验。切勿在生产环境使用这也是模板文件头部注释明确强调的。运行开发模式Step 7在umbraco-app项目目录中执行npm install npm run dev # 或 yarn install yarn dev博客即可在http://localhost:3000访问。对应 package.json 中的 scriptsdev为next、build为next build、start为next start。Preview Mode 原理剖析Step 8如果在 Umbraco 中修改文章但不发布默认情况下http://localhost:3000不会显示这些变更。开启Preview Mode后就能看到未发布的内容。原文档给出的操作方式进入http://localhost:3000/api/preview?secretsecret开启预览secret即.env.local中的UMBRACO_PREVIEW_SECRET访问修改过的文章页即可看到未发布变更访问http://localhost:3000/api/exit-preview退出预览。结合示例源码可以看到其完整实现链路1. 开启预览—— pages/api/preview.tsconst { secret } req.query; // Check the secret and next parameters // This secret should only be known by this API route if (!secret) { return res.status(401).json({ message: No token provided }); } if (secret ! process.env.UMBRACO_PREVIEW_SECRET) { return res.status(401).json({ message: Invalid token }); } res.setDraftMode({ enable: true }); res.redirect(/);路由先校验查询参数secret与环境变量UMBRACO_PREVIEW_SECRET是否一致不一致返回 401再调用res.setDraftMode({ enable: true })写入 Draft Mode Cookie最后重定向回首页。2. 退出预览—— pages/api/exit-preview.tsres.setDraftMode({ enable: false }); res.writeHead(307, { Location: / }); res.end();通过setDraftMode({ enable: false })删除 Draft Mode Cookie并以 307 重定向回首页。3. 预览如何传递到数据层Next.js 在 Draft Mode 下会把preview: boolean注入getStaticProps/getStaticPaths。pages/posts/[slug].tsx 中export async function getStaticPaths({ preview }: { preview: boolean }) { const slugs await getAllPostSlugs(preview); return { paths: slugs.map((slug) /posts${slug}), fallback: false, }; }该preview一路传到 lib/api.ts 的fetchSingle/fetchMultiple作为 Delivery API 请求头Preview: true/false发出见下文。也就是说Umbraco 侧的ApiKey认证 Next.js 侧的Preview请求头共同决定了是否返回未发布内容这正是 Step 3 中ApiKey配置仅预览时需要的原因。静态生成数据抓取Delivery API 查询细节源码剖析所有对 Umbraco 的 HTTP 请求集中在 lib/api.ts。从源码结构看其请求模式为Base URL${UMBRACO_SERVER_URL}/umbraco/delivery/api/v2/content即 Delivery API v2 端点统一请求头Start-Item指定查询起点节点本示例为posts、Api-Key、Preview两个核心请求单条GET {base}/item/{slug}用于文章详情fetchSingle多条GET {base}/?{query}用于文章列表fetchMultiple。列表查询参数见 fetchPostsreturn await fetchMultiple( fetchchildren:/expand${expand}sortupdateDate:desctake${take}, posts, preview, );参数含义fetchchildren:/抓取Start-Item节点posts下的直接子级expandproperties[author]展开文章上的 author 属性将作者内联返回省去二次请求首页/详情页列表需要而纯 slug 列表不需要sortupdateDate:desc按更新时间倒序take${take}限制条数详情场景取 3、首页取 10、slug 列表取 100返回数据的抽取逻辑将 Delivery API 的原始结构映射为前端模型types/post.tsid、slug、title、coverImage、date、author、excerpt、content、tagsconst extractSlug (item: any): string item.route.path; const extractPost (post: any): Post { // NOTE: author is an expanded property on the post const author extractAuthor(post.properties.author); return { id: post.id, slug: extractSlug(post), title: post.name, coverImage: { url: ${UMBRACO_SERVER_URL}${post.properties.coverImage[0].url}, }, date: post.updateDate, author: author, excerpt: post.properties.excerpt, content: post.properties.content.markup, tags: post.properties.tags, }; };几个值得注意的实现细节slug 取自route.path即 Umbraco 内容节点的发布路由而非内容 ID图片 URL 需要拼接UMBRACO_SERVER_URLDelivery API 返回的图片是相对路径前端补全为绝对地址正文为properties.content.markupRTE 富文本的 HTML由 components/post-body.tsx 通过dangerouslySetInnerHTML渲染详情页的相关文章getPostAndMorePosts 在取完当前文章后再拉 3 篇最新文章过滤掉当前文章自身后取前 2 篇作为morePosts。对应的页面数据入口为首页 pages/index.tsx 的getStaticProps调用getAllPostsForHome(preview)取 10 篇、展开 author第一篇作为 hero post其余进入 More Stories 列表详情页 pages/posts/[slug].tsx 的getStaticPaths调用getAllPostSlugs(preview)取 100 篇、不展开 author减少不必要的数据传输并设置fallback: false——只构建 slug 列表中存在的文章其余路由返回 404。关于查询效率原文档特别指出Content Delivery API 本身功能丰富但本示例为控制复杂度省略了部分特性与优化存在轻微 over-fetching过度抓取尤其在一次拉取多篇文章时例如为取 slug 列表而取回 100 篇文章的完整结构。生产项目中可按需裁剪expand与fields参数。关键配置细节1.next/image图片域名白名单文章封面图直接来自 Umbraco 服务器因此 next.config.js 从环境变量解析出域名并加入白名单module.exports { images: { // add the Umbraco server domain as allowed domain for serving images domains: [process.env.UMBRACO_SERVER_URL.match(/.*\/\/([^:/]*).*/)[1]], }, };从源码结构看这里用正则从UMBRACO_SERVER_URL中截取主机名——因此该环境变量必须是带协议的完整 URL如https://localhost:12345否则域名解析会失败。2. 组件与样式页面由 components/ 下的 17 个组件拼装hero-post、post-preview、post-header、more-stories 等样式采用 Tailwind CSS Modulesstyles/index.css、tailwind.config.js与博客视觉呈现无关的读者可以跳过。部署Step 9原文档给出的部署要点先部署 Umbraco博客上线前必须先将 Umbraco 站点部署到某云厂商使博客数据对生产环境可访问Azure 部署需遵循 Umbraco 官方的 Azure Web Apps 指南也可使用 Umbraco Cloud再部署 Next.js 应用将项目推送到代码托管平台并导入 Vercel关键步骤——同步环境变量导入项目后务必在 Vercel 的Environment Variables中把UMBRACO_SERVER_URL、UMBRACO_DELIVERY_API_KEY、UMBRACO_PREVIEW_SECRET设置为与 Umbraco 生产部署一致的值生产环境不要再携带NODE_TLS_REJECT_UNAUTHORIZED0该开关仅为本地自签证书场景服务。小结该示例完整演示了一条无头 CMS 静态生成的落地链路环节机制内容管理Umbraco backoffice Delivery APIEnabled: trueApiKey数据抓取构建/请求时fetchDelivery API v2expand/sort/take控制查询静态渲染getStaticPathsfallback: falsegetStaticProps预渲染文章页草稿预览/api/preview校验 secret 后setDraftMode({ enable: true })Draft Mode 触发带Preview: true请求头的重新生成图片Umbraco 域名经next.config.js加入images.domains白名单如果你需要在自建 Umbraco 站点上复刻这套流程直接以 examples/cms-umbraco 为模板、按本文 Step 19 执行即可调整内容模型时重点参照 lib/api.ts 的extractPost映射与 types/post.ts 的数据结构。【免费下载链接】next.jsThe React Framework项目地址: https://gitcode.com/GitHub_Trending/next/next.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考