设置预览功能 NewThis content is new.
¥Setting up the Preview feature NewThis content is new.
Strapi 的预览功能可以直接从 Strapi 管理面板预览前端应用中的内容。
¥Strapi's Preview feature enables previewing content in a frontend application directly from the Strapi admin panel.
本页介绍了如何在 Strapi 中设置预览功能。设置完成后,该功能可按照 用户指南 中的说明使用。
¥The present page describes how to set up the Preview feature in Strapi. Once set up, the feature can be used as described in the User Guide.
-
必须在你的
.env
文件中定义以下环境变量,用适当的值替换示例值:¥The following environment variables must be defined in your
.env
file, replacing example values with appropriate values:CLIENT_URL=https://your-frontend-app.com
PREVIEW_SECRET=your-secret-key # optional, required with Next.js draft mode -
应该已经创建并设置了你的 Strapi 项目的前端应用。
¥A front-end application for your Strapi project should be already created and set up.
配置组件
¥Configuration components
预览功能配置存储在 config/admin
文件 的 preview
对象中,由 3 个关键组件组成:
¥The Preview feature configuration is stored in the preview
object of the config/admin
file and consists of 3 key components:
激活标志
¥Activation flag
启用或禁用预览功能:
¥Enables or disables the preview feature:
// …
preview: {
enabled: true,
// …
}
// …
允许的来源
¥Allowed origins
控制哪些域被允许加载到管理面板中的 iframe 中以预览内容:
¥Controls which domains are allowed to be loaded in an iframe in your admin panel to preview content:
// …
preview: {
enabled: true,
config: {
allowedOrigins: [env("CLIENT_URL")], // Usually your frontend application URL
// …
}
}
// …
预览处理程序
¥Preview handler
管理预览逻辑和 URL 生成,如以下基本示例所示,其中 uid
是内容类型标识符(例如,api::article.article
或 plugin::my-api.my-content-type
):
¥Manages the preview logic and URL generation, as in the following basic example where uid
is the content-type identifier (e.g., api::article.article
or plugin::my-api.my-content-type
):
// …
preview: {
enabled: true,
config: {
// …
async handler(uid, { documentId, locale, status }) {
const document = await strapi.documents(uid).findOne({ documentId });
const pathname = getPreviewPathname(uid, { locale, document });
return `${env('PREVIEW_URL')}${pathname}`
},
}
}
// …
以下基本实现指南中给出了 URL 生成逻辑 的示例。
¥An example of URL generation logic in given in the following basic implementation guide.
预览草稿条目
¥Previewing draft entries
前端应用查询草稿或已发布内容的策略是特定于框架的。至少存在 3 种策略:
¥The strategy for the front end application to query draft or published content is framework-specific. At least 3 strategies exist:
-
使用查询参数,具有类似
/your-path?preview=true
的内容(例如,Nuxt 的工作方式)¥using a query parameter, having something like
/your-path?preview=true
(this is, for instance, how Nuxt works) -
重定向到专用的预览路线,如
/preview?path=your-path
(例如,Next 的草稿模式 的工作方式)¥redirecting to a dedicated preview route like
/preview?path=your-path
(this is, for instance, how Next's draft mode works) -
或使用不同的域进行预览,如
preview.mysite.com/your-path
。¥or using a different domain for previews like
preview.mysite.com/your-path
.
当为你的内容类型启用 起草并发布 时,你还可以直接利用 Strapi 的 status
参数来处理预览处理程序中的逻辑,使用以下通用方法:
¥When Draft & Publish is enabled for your content-type, you can also directly leverage Strapi's status
parameter to handle the logic within the Preview handler, using the following generic approach:
async handler(uid, { documentId, locale, status }) {
const document = await strapi.documents(uid).findOne({ documentId });
const pathname = getPreviewPathname(uid, { locale, document });
if (status === 'published') {
// return the published version
}
// return the draft version
},
基本实现指南 中给出了使用 Next.js 草稿模式的更详细示例。
¥A more detailed example using the draft mode of Next.js is given in the basic implementation guide.
基本实现指南
¥Basic implementation guide
按照以下步骤将预览功能添加到你的内容类型。
¥Follow these steps to add Preview capabilities to your content types.
1. 创建预览配置
¥ Create the Preview configuration
创建一个新的文件 /config/admin.ts
(如果存在则更新它),具有以下基本结构:
¥Create a new file /config/admin.ts
(or update it if it exists) with the following basic structure:
export default ({ env }) => ({
// Other admin-related configurations go here
// (see docs.strapi.io/dev-docs/configurations/admin-panel)
preview: {
enabled: true,
config: {
allowedOrigins: env('CLIENT_URL'),
async handler (uid, { documentId, locale, status }) => {
// Handler implementation coming in step 3
},
},
},
});
2. 添加 URL 生成逻辑
¥ Add URL generation logic
使用 getPreviewPathname
函数添加 URL 生成逻辑。以下示例取自 启动板 Strapi 演示应用:
¥Add the URL generation logic with a getPreviewPathname
function. The following example is taken from the Launchpad Strapi demo application:
// Function to generate preview pathname based on content type and document
const getPreviewPathname = (uid, { locale, document }): string => {
const { slug } = document;
// Handle different content types with their specific URL patterns
switch (uid) {
// Handle pages with predefined routes
case "api::page.page":
switch (slug) {
case "homepage":
return `/${locale}`; // Localized homepage
case "pricing":
return "/pricing"; // Pricing page
case "contact":
return "/contact"; // Contact page
case "faq":
return "/faq"; // FAQ page
}
// Handle product pages
case "api::product.product": {
if (!slug) {
return "/products"; // Products listing page
}
return `/products/${slug}`; // Individual product page
}
// Handle blog articles
case "api::article.article": {
if (!slug) {
return "/blog"; // Blog listing page
}
return `/blog/${slug}`; // Individual article page
}
default: {
return null;
}
}
};
// … main export (see step 3)
如果没有意义,某些内容类型不需要预览,因此默认情况返回 null
。例如,具有一些站点元数据的全局单一类型将没有匹配的前端页面。在这些情况下,处理程序函数应返回 null
,并且预览 UI 将不会显示在管理面板中。这是你为每种内容类型启用或禁用预览的方式。
¥Some content types don't need to have a preview if it doesn't make sense, hence the default case returning null
. A Global single type with some site metadata, for example, will not have a matching front-end page. In these cases, the handler function should return null
, and the preview UI will not be shown in the admin panel. This is how you enable or disable preview per content type.
3. 添加处理程序逻辑
¥ Add handler logic
创建完整配置,扩展在步骤 1 中创建的基本配置。使用在步骤 2 中创建的 URL 生成逻辑,添加适当的处理程序逻辑:
¥Create the complete configuration, expanding the basic configuration created in step 1. with the URL generation logic created in step 2., adding an appropriate handler logic:
const getPreviewPathname = (uid, { locale, document }): string => {
// … as defined in step 2
};
// Main configuration export
export default ({ env }) => {
// Get environment variables
const clientUrl = env("CLIENT_URL"); // Frontend application URL
const previewSecret = env("PREVIEW_SECRET"); // Secret key for preview authentication
return {
// Other admin-related configurations go here
// (see docs.strapi.io/dev-docs/configurations/admin-panel)
preview: {
enabled: true, // Enable preview functionality
config: {
allowedOrigins: clientUrl, // Restrict preview access to specific domain
async handler(uid, { documentId, locale, status }) {
// Fetch the complete document from Strapi
const document = await strapi.documents(uid).findOne({ documentId });
// Generate the preview pathname based on content type and document
const pathname = getPreviewPathname(uid, { locale, document });
// Disable preview if the pathname is not found
if (!pathname) {
return null;
}
// Use Next.js draft mode passing it a secret key and the content-type status
const urlSearchParams = new URLSearchParams({
url: pathname,
secret: previewSecret,
status,
});
return `${clientUrl}/api/preview?${urlSearchParams}`;
},
},
},
};
};
4. 设置前端预览路线
¥ Set up the front-end preview route
设置前端预览路线高度依赖于前端应用使用的框架。
¥Setting up the front-end preview route is highly dependent on the framework used for your front-end application.
例如,Next.js 草稿模式 和 Nuxt 预览模式 在各自的文档中提供了有关如何实现前端部分的附加文档。
¥For instance, Next.js draft mode and Nuxt preview mode provide additional documentation on how to implement the front-end part in their respective documentations.
如果使用 Next.js,基本实现可能类似于以下取自 启动板 Strapi 演示应用的示例:
¥If using Next.js, a basic implementation could be like in the following example taken from the Launchpad Strapi demo application:
import { draftMode } from "next/headers";
import { redirect } from "next/navigation";
export async function GET(request: Request) {
// Parse query string parameters
const { searchParams } = new URL(request.url);
const secret = searchParams.get("secret");
const url = searchParams.get("url");
const status = searchParams.get("status");
// Check the secret and next parameters
// This secret should only be known to this route handler and the CMS
if (secret !== process.env.PREVIEW_SECRET) {
return new Response("Invalid token", { status: 401 });
}
// Enable Draft Mode by setting the cookie
if (status === "published") {
draftMode().disable();
} else {
draftMode().enable();
}
// Redirect to the path from the fetched post
// We don't redirect to searchParams.slug as that might lead to open redirect vulnerabilities
redirect(url || "/");
}
5. 允许嵌入前端
¥ Allow the front-end to be embedded
在 Strapi 方面,allowedOrigins
配置参数 允许管理面板在 iframe 中加载前端窗口。但允许嵌入是双向的,因此在前端,你还需要允许窗口嵌入到 Strapi 的管理面板中。
¥On the Strapi side, the allowedOrigins
configuration parameter allows the admin panel to load the front-end window in an iframe. But allowing the embedding works both ways, so on the front-end side, you also need to allow the window to be embedded in Strapi's admin panel.
这要求前端应用具有自己的标头指令,即 CSP frame-ancestors
指令。设置此指令取决于你的网站是如何构建的。例如,在 Next.js 中设置此功能需要中间件配置(参见 Next.js 文档)。
¥This requires the front-end application to have its own header directive, the CSP frame-ancestors
directive. Setting this directive up depends on how your website is built. For instance, setting this up in Next.js requires a middleware configuration (see Next.js docs).
后续步骤
¥Next steps
设置预览系统后,你需要调整数据获取逻辑以适当处理草稿内容。这涉及:
¥Once the preview system is set up, you need to adapt your data fetching logic to handle draft content appropriately. This involves:
-
创建或调整你的数据获取实用程序以检查是否启用了草稿模式
¥Create or adapt your data fetching utility to check if draft mode is enabled
-
更新 API 调用以在适当时包含草稿状态参数
¥Update your API calls to include the draft status parameter when appropriate
以下内容取自 启动板 Strapi 演示应用,是如何在你的 Next.js 前端应用中实现草稿感知数据获取的示例:
¥The following, taken from the Launchpad Strapi demo application, is an example of how to implement draft-aware data fetching in your Next.js front-end application:
import { draftMode } from "next/headers";
import qs from "qs";
export default async function fetchContentType(
contentType: string,
params: Record = {}
): Promise {
// Check if Next.js draft mode is enabled
const { isEnabled: isDraftMode } = draftMode();
try {
const queryParams = { ...params };
// Add status=draft parameter when draft mode is enabled
if (isDraftMode) {
queryParams.status = "draft";
}
const url = `${baseURL}/${contentType}?${qs.stringify(queryParams)}`;
const response = await fetch(url);
if (!response.ok) {
throw new Error(
`Failed to fetch data from Strapi (url=${url}, status=${response.status})`
);
}
return await response.json();
} catch (error) {
console.error("Error fetching content:", error);
throw error;
}
}
然后可以在页面组件中使用此实用方法根据预览状态获取草稿或已发布的内容:
¥This utility method can then be used in your page components to fetch either draft or published content based on the preview state:
// In your page component:
const pageData = await fetchContentType('api::page.page', {
// Your other query parameters
});