# 账户账单详情 Source: https://docs.strapi.io/cloud/account/account-billing # 账户账单与发票 {#account-billing--invoices} 🌐 Account billing & invoices 通过 *个人资料* 页面,可通过点击界面右上角的头像,然后点击 **个人资料** 访问,你可以进入 [ *账单*](#account-billing) 和 [ *发票*](#account-invoices) 标签页。 ## 账户计费 {#account-billing} 🌐 Account billing *账单*标签显示并允许你修改账户设置的账单详细信息和付款方式。 *账单*标签的*支付方式*部分允许你管理可用于 Strapi Cloud 项目的信用卡。*账单详情*部分需要填写,至少要填写必填字段,因为这些信息将作为与你的账户相关的所有 Strapi Cloud 项目的默认账单详情。 ### 添加新的信用卡 {#adding-a-new-credit-card} 🌐 Adding a new credit card 1. 在 *账单*选项卡的*付款方式*部分,点击**添加银行卡**按钮。 2. 填写以下字段: | 字段名称 | 描述 || --- | --- || 卡号 | 输入要添加为支付方式的信用卡号码。 || 到期日 | 输入信用卡的到期日期。 || CVC | 输入显示在信用卡背面的三位数代码。 | 3. 点击 **保存** 按钮。 :::tip 第一个被添加为账户付款方式的信用卡默认将是主要信用卡。然而,可以通过点击 图标,然后选择**设为主要**来将另一张信用卡设为主要信用卡。 ::: ### 删除信用卡 {#deleting-a-credit-card} 🌐 Deleting a credit card 要从账户的支付方式列表中移除信用卡: 🌐 To remove a credit card from the list of payment methods for the account: 1. 点击你希望删除的信用卡的 图标。 2. 点击 **移除卡片**。卡片会立即被删除。 :::note 你无法删除主要信用卡,因为至少必须有一张信用卡可用作支付方式,而主要信用卡默认就是那一张。如果你希望删除的信用卡当前是主要信用卡,则必须先将另一张信用卡设为主要信用卡,然后再删除它。 🌐 You cannot delete the primary card as at least one credit card must be available as payment method, and the primary card is by default that one. If the credit card you wish to delete is currently the primary card, you must first define another credit card as primary, then delete it. ::: ## 账户发票 {#account-invoices} 🌐 Account invoices *发票* 选项卡显示你所有 Strapi Cloud 项目的完整发票列表。 :::strapi Invoices are also available per project. 在任何项目的 *设置 > 发票* 选项卡中,你将只找到该项目的发票。请随时查看[专门文档](/cloud/projects/settings#invoices)。 🌐 In the *Settings > Invoices* tab of any project, you will find the invoices for that project only. Feel free to check the [dedicated documentation](/cloud/projects/settings#invoices). ::: # 个人资料设置 Source: https://docs.strapi.io/cloud/account/account-settings # 个人资料设置 {#profile-settings} 🌐 Profile settings *个人资料* 页面使你能够管理你的账户详细信息和偏好设置。你可以通过点击界面右上角的个人头像,然后选择 **个人资料** 来访问该页面。 🌐 The *Profile* page enables you to manage your account details and preferences. It is accessible by clicking on your profile picture, on the top right hand corner of the interface, and **Profile**. *个人资料*界面中有3个可用选项卡: [*常规*](#general)、 *账单* 和 发票(后两个在本指南的[账户账单详情](/cloud/account/account-billing)部分有说明)。 ## 一般 {#general} 🌐 General “ *常规*”选项卡允许你编辑账户资料的以下详细信息: - 详情:查看与你的账户关联的名称。 - 已连接的账户:用于管理与你的 Strapi Cloud 账户关联的 Google、GitHub、GitLab 和电子邮件账户(请参阅 [管理已连接的账户](#managing-connected-accounts))。 - 删除账户:永久删除你的 Strapi Cloud 账户(参见 [删除 Strapi Cloud 账户](#deleting-strapi-cloud-account))。 ### 管理已连接的账户 {#managing-connected-accounts} 🌐 Managing connected accounts 你可以将 Google、GitLab、GitHub 和电子邮件账户连接到你的 Strapi Cloud 账户。_已连接账户_ 部分列出了当前已连接到你的 Strapi Cloud 账户的账户。在此处,如果尚未连接,你也可以连接新的 Google、GitLab、GitHub 和电子邮件账户。 🌐 You can connect a Google, GitLab, GitHub and email account to your Strapi Cloud account. The _Connected accounts_ section lists accounts that are currently connected to your Strapi Cloud account. From there you can also connect a new Google, GitLab, GitHub and email account if one is not already connected. 要将新的 Google、GitLab、GitHub 或电子邮件账户连接到你的 Strapi Cloud 账户,请点击 **连接账户** 按钮,并按照相应网站上的下一步操作进行操作。 🌐 To connect a new Google, GitLab, GitHub or email account to your Strapi Cloud account, click on the **Connect account** button and follow the next steps on the corresponding website. 你还可以点击已连接账户的三点按钮,然后点击“在……上管理”按钮,直接在相应网站上管理你的 GitHub、GitLab 或 Google 账户。 🌐 You can also click on the three dots button of a connected account and click on the "Manage on" button to manage your GitHub, GitLab or Google account directly on the corresponding website. ### 删除 Strapi Cloud 账户 {#deleting-strapi-cloud-account} 🌐 Deleting Strapi Cloud account 你可以删除你的 Strapi Cloud 账户,但这是永久且不可逆的。所有相关的项目及其数据也将被删除,项目的订阅将自动取消。 🌐 You can delete your Strapi Cloud account, but it will be permanent and irreversible. All associated projects and their data will be deleted as well and the subscriptions for the projects will automatically be canceled. 1. 在 *常规*选项卡的*删除账户*部分,点击**删除账户**按钮。 2. 在对话框中,在文本框里输入 `DELETE`。 3. 通过点击 **删除** 按钮确认删除你的账户。 # 数据库 Source: https://docs.strapi.io/cloud/advanced/database # 数据库 {#database} 🌐 Database Strapi Cloud 默认提供预配置的 PostgreSQL 数据库。但是,如果需要,你也可以将其配置为使用外部 SQL 数据库。 🌐 Strapi Cloud provides a pre-configured PostgreSQL database by default. However, you can also configure it to utilize an external SQL database, if needed. :::prerequisites - 一个在 `v4.8.2+` 上运行的本地 Strapi 项目。 - 外部数据库的凭证。 - 如果使用现有数据库,模式必须与 Strapi 项目的模式匹配。 ::: :::caution 虽然可以在 Strapi Cloud 中使用外部数据库,但在使用时应考虑以下事项: 🌐 While it's possible to use an external database with Strapi Cloud, you should do it while keeping in mind the following considerations: - Strapi Cloud 已经提供了一个为 Strapi 优化的托管数据库。 - 使用外部数据库可能导致意外行为和/或性能问题(例如,网络延迟可能影响性能)。出于性能原因,建议将外部数据库托管在与你的 Strapi Cloud 项目所在地区接近的位置。你可以在项目设置中找到你的 Strapi Cloud 项目托管位置(见 [项目设置 > 常规 > 选择的地区](/cloud/projects/settings#general))。 - Strapi 无法为与 Strapi Cloud 一起使用的外部数据库提供安全性或支持。 ::: :::warning 任何添加到你的项目中以 `DATABASE_` 开头的环境变量都将导致 Strapi Cloud 假定你将使用外部数据库,并且所有 Strapi Cloud 特定的数据库变量都不会被注入! 🌐 Any environment variable added to your project that starts with `DATABASE_` will cause Strapi Cloud to assume that you will be using an external database and all Strapi Cloud specific database variables will not be injected! ::: ## 配置 {#configuration} 🌐 Configuration 项目 `./config/database.js` 或 `./config/database.ts` 文件必须与 [数据库配置中的环境变量](https://strapi.nodejs.cn/cms/configurations/database#environment-variables-in-database-configurations) 部分中的配置匹配。 🌐 The project `./config/database.js` or `./config/database.ts` file must match the configuration found in the [environment variables in database configurations](https://strapi.nodejs.cn/cms/configurations/database#environment-variables-in-database-configurations) section. 在推送更改之前,将环境变量添加到 Strapi Cloud 项目中: 🌐 Before pushing changes, add environment variables to the Strapi Cloud project: 1. 登录 Strapi Cloud,然后在“项目”页面上点击相应的项目。 2. 点击 **设置** 标签,然后在左侧菜单中选择 **变量**。 3. 添加以下环境变量: | 变量 | 值 | 详情 || -------------------------------- | ---------------- | ---------- || `DATABASE_CLIENT` | your_db | 应该是 `mysql`、`postgres` 或 `sqlite` 之一。 || `DATABASE_HOST` | your_db_host | 数据库主机的 URL 或 IP 地址 || `DATABASE_PORT` | your_db_port | 用于访问数据库的端口 || `DATABASE_NAME` | your_db_name | 数据库名称 || `DATABASE_USERNAME` | your_db_username | 用于访问数据库的用户名 || `DATABASE_PASSWORD` | your_db_password | 与该用户名关联的密码 || `DATABASE_SSL_REJECT_UNAUTHORIZED` | false | 是否应拒绝未经授权的连接 || `DATABASE_SCHEMA` | public | - | 4. 点击 **保存**。 :::caution 为了确保顺利部署,建议不要更改环境变量的名称。 🌐 To ensure a smooth deployment, it is recommended to not change the names of the environment variables. ::: ## 部署 {#deployment} 🌐 Deployment 要部署项目并使用外部数据库,请推送之前的更改。这将触发 Strapi Cloud 项目的重新构建和新的部署。 🌐 To deploy the project and utilize the external database, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. 一旦应用完成构建,项目将使用外部数据库。 🌐 Once the application finishes building, the project will use the external database. ## 恢复到默认数据库 {#reverting-to-the-default-database} 🌐 Reverting to the default database 要恢复到默认数据库,请从 Strapi Cloud 项目仪表板中删除之前添加的与外部数据库相关的环境变量,然后保存。要使更改生效,你必须重新部署 Strapi Cloud 项目。 🌐 To revert back to the default database, remove the previously added environment variables related to the external database from the Strapi Cloud project dashboard, and save. For the changes to take effect, you must redeploy the Strapi Cloud project. # 电子邮件提供商 Source: https://docs.strapi.io/cloud/advanced/email # Strapi Cloud 的电子邮件提供商配置 {#email-providers-configuration-for-strapi-cloud} 🌐 Email Providers configuration for Strapi Cloud Strapi Cloud 开箱即用自带一个基础的电子邮件提供商。不过,如果需要,它也可以配置为使用其他电子邮件提供商。 🌐 Strapi Cloud comes with a basic email provider out of the box. However, it can also be configured to utilize another email provider, if needed. :::caution 请注意,Strapi 无法为第三方电子邮件提供商提供支持。 🌐 Please be advised that Strapi is unable to provide support for third-party email providers. ::: :::prerequisites - 一个在 `v4.8.2+` 上运行的本地 Strapi 项目。 - 另一个电子邮件提供商的凭据(请参见 :::caution 文件结构必须与上述路径完全匹配,否则配置将不会应用到 Strapi 云。 🌐 The file structure must match the above path exactly, or the configuration will not be applied to Strapi Cloud. ::: 每个提供商将有不同的配置设置可用。请查看 :::tip 在将上述更改推送到 GitHub 之前,向 Strapi Cloud 项目添加环境变量,以防在更改完成之前触发项目的重建和新部署。 🌐 Before pushing the above changes to GitHub, add environment variables to the Strapi Cloud project to prevent triggering a rebuild and new deployment of the project before the changes are complete. ::: ### Strapi 云配置 {#strapi-cloud-configuration} 🌐 Strapi Cloud Configuration 1. 登录 Strapi Cloud,然后在“项目”页面上点击相应的项目。 2. 点击 **设置** 标签,然后在左侧菜单中选择 **变量**。 3. 添加电子邮件提供商特定的所需环境变量。 4. 点击 **保存**。 **示例:** ## 部署 {#deployment} 🌐 Deployment 要部署项目并使用其他方的电子邮件提供商,请推送之前的更改。这将触发 Strapi Cloud 项目的重建和新部署。 🌐 To deploy the project and utilize another party email provider, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. 一旦应用构建完成,项目将使用新的电子邮件提供商。 🌐 Once the application finishes building, the project will use the new email provider. :::strapi Custom Provider 如果你想创建自定义电子邮件提供商,请参阅 CMS 文档中的 [电子邮件提供商](/cms/features/email#providers) 文档。 🌐 If you want to create a custom email provider, please refer to the [Email providers](/cms/features/email#providers) documentation in the CMS Documentation. ::: # 为 Strapi Cloud 上传提供商配置 Source: https://docs.strapi.io/cloud/advanced/upload # 为 Strapi Cloud 上传提供商配置 {#upload-provider-configuration-for-strapi-cloud} 🌐 Upload Provider Configuration for Strapi Cloud Strapi Cloud 开箱即用带有本地上传提供者。不过,如果需要,它也可以配置为使用第三方上传提供者。 🌐 Strapi Cloud comes with a local upload provider out of the box. However, it can also be configured to utilize a third-party upload provider, if needed. :::caution 请注意,Strapi 无法为第三方上传提供商提供支持。 🌐 Please be advised that Strapi is unable to provide support for third-party upload providers. ::: :::prerequisites - 一个在 `v4.8.2+` 上运行的本地 Strapi 项目。 - 第三方上传提供者的凭证(参见 :::caution 文件结构必须与上述路径完全匹配,否则配置将不会应用到 Strapi 云。 🌐 The file structure must match the above path exactly, or the configuration will not be applied to Strapi Cloud. ::: 每个提供商将有不同的配置设置可用。请查看 ### 配置安全中间件 {#configure-the-security-middleware} 🌐 Configure the Security Middleware 由于 Strapi 安全中间件的默认设置,你需要修改 `contentSecurityPolicy` 设置才能在媒体库中正确查看缩略图预览。 🌐 Due to the default settings in the Strapi Security Middleware you will need to modify the `contentSecurityPolicy` settings to properly see thumbnail previews in the Media Library. 在你的 Strapi 项目中执行此操作: 🌐 To do this in your Strapi project: 1. 在你的 Strapi 项目中,导航到 `./config/middlewares.js` 或 `./config/middlewares.ts`。 2. 用上传提供者提供的对象替换默认的 `strapi::security` 字符串。 **示例:** :::tip 在将上述更改推送到 GitHub 之前,向 Strapi Cloud 项目添加环境变量,以防在更改完成之前触发项目的重建和新部署。 🌐 Before pushing the above changes to GitHub, add environment variables to the Strapi Cloud project to prevent triggering a rebuild and new deployment of the project before the changes are complete. ::: ### Strapi 云配置 {#strapi-cloud-configuration} 🌐 Strapi Cloud Configuration 1. 登录 Strapi Cloud,然后在“项目”页面上点击相应的项目。 2. 点击 **设置** 标签,然后在左侧菜单中选择 **变量**。 3. 添加特定于上传提供者的所需环境变量。 4. 点击 **保存**。 **示例:** ## 部署 {#deployment} 🌐 Deployment 要部署项目并使用第三方上传提供商,请推送之前的更改。这将触发 Strapi Cloud 项目的重新构建和新部署。 🌐 To deploy the project and utilize the third-party upload provider, push the changes from earlier. This will trigger a rebuild and new deployment of the Strapi Cloud project. 一旦应用构建完成,项目将使用新的上传提供者。 🌐 Once the application finishes building, the project will use the new upload provider. :::strapi Custom Provider 如果你想创建自定义上传提供程序,请参阅 CMS 文档中的 [Providers](/cms/features/media-library#providers) 文档。 🌐 If you want to create a custom upload provider, please refer to the [Providers](/cms/features/media-library#providers) documentation in the CMS Documentation. ::: # 命令行接口 (CLI) {#command-line-interface-cli} Source: https://docs.strapi.io/cloud/cli/cloud-cli # 命令行接口 (CLI) {#command-line-interface-cli} 🌐 Command Line Interface (CLI) Strapi Cloud 配备了一个命令行接口(CLI),允许你登录和登出,并在不需要将本地项目托管在远程 git 仓库的情况下进行部署。CLI 支持 `yarn` 和 `npm` 两种包管理器。 🌐 Strapi Cloud comes with a Command Line Interface (CLI) which allows you to log in and out, and to deploy a local project without it having to be hosted on a remote git repository. The CLI works with both the `yarn` and `npm` package managers. :::note 建议仅在本地安装 Strapi,这需要在所有以下 `strapi` 命令前加上用于项目设置的包管理器(例如 `npm run strapi help` 或 `yarn strapi help`)或专用的 node 包执行器(例如 `npx strapi help`)。 🌐 It is recommended to install Strapi locally only, which requires prefixing all of the following `strapi` commands with the package manager used for the project setup (e.g `npm run strapi help` or `yarn strapi help`) or a dedicated node package executor (e.g. `npx strapi help`). ::: ## Strapi 登录 {#strapi-login} 🌐 strapi login **别名:** `strapi cloud:login` 登录 Strapi 云。 🌐 Log in Strapi Cloud. ```bash strapi login ``` 此命令会自动打开一个浏览器窗口,首先要求你确认浏览器窗口和终端中显示的代码是否相同。然后,你将能够通过 Google、GitHub 或 GitLab 登录 Strapi Cloud。一旦浏览器窗口确认登录成功,就可以安全关闭。 🌐 This command automatically opens a browser window to first ask you to confirm that the codes displayed in both the browser window and the terminal are the same. Then you will be able to log into Strapi Cloud via Google, GitHub or GitLab. Once the browser window confirms successful login, it can be safely closed. 如果浏览器窗口没有自动打开,终端将显示一个可点击的链接以及可手动输入的代码。 🌐 If the browser window doesn't automatically open, the terminal will display a clickable link as well as the code to enter manually. ## strapi 部署 {#strapi-deploy} 🌐 strapi deploy **别名:** `strapi cloud:deploy` 在 Strapi Cloud 中部署一个新的本地项目(< 100MB)。 🌐 Deploy a new local project (< 100MB) in Strapi Cloud. ```bash strapi deploy ``` 此命令必须在 `login` 命令之后使用。它可以将本地 Strapi 项目部署到 Strapi Cloud,而无需事先将其托管在远程 git 仓库中。终端将在项目成功部署到 Strapi Cloud 时通知你。 🌐 This command must be used after the `login` one. It deploys a local Strapi project on Strapi Cloud, without having to host it on a remote git repository beforehand. The terminal will inform you when the project is successfully deployed on Strapi Cloud. 通过 CLI 部署 Strapi 项目会在免费计划上创建一个项目。 🌐 Deploying a Strapi project through the CLI creates a project on the Free plan. 一旦项目首次通过 CLI 部署到 Strapi Cloud,`deploy` 命令可以被重复使用以触发同一项目的新部署。 🌐 Once the project is first deployed on Strapi Cloud with the CLI, the `deploy` command can be reused to trigger a new deployment of the same project. :::note 一旦你部署了你的项目,如果你访问 Strapi Cloud 仪表板,你可能会看到一些限制,以及由于创建了一个不在远程仓库中的 Strapi Cloud 项目并通过 CLI 部署而产生的影响。 🌐 Once you deployed your project, if you visit the Strapi Cloud dashboard, you may see some limitations as well as impacts due to creating a Strapi Cloud project that is not in a remote repository and which was deployed with the CLI. - 仪表板中通常用于显示关于 Git 提供者信息的某些区域将会是空白的。 - 某些按钮,例如 **触发部署** 按钮,将会是灰色且无法点击,因为除非你已经[将 Git 仓库连接到你的 Strapi 云项目](/cloud/getting-started/deployment-cli#automatically-deploying-subsequent-changes)。 ::: ## strapi 链接 {#strapi-link-newbadge-} 🌐 strapi link **别名:** `strapi cloud:link` 将当前文件夹中的项目链接到 Strapi Cloud 中的现有项目。 🌐 Links project in the current folder to an existing project in Strapi Cloud. ```bash strapi link ``` 此命令将你当前目录中的本地项目与你 Strapi Cloud 账户上的现有项目连接。系统将提示你从 Strapi Cloud 上托管的可用项目列表中选择你希望链接的项目。 🌐 This command connects your local project in the current directory with an existing project on your Strapi Cloud account. You will be prompted to select the project you wish to link from a list of available projects hosted on Strapi Cloud. ## strapi 项目 {#strapi-projects-newbadge-} 🌐 strapi projects **别名:** `strapi cloud:projects` 列出与你的账户关联的所有 Strapi Cloud 项目。 🌐 Lists all Strapi Cloud projects associated with your account. ```bash strapi projects ``` 此命令检索并显示托管在你的 Strapi Cloud 账户上的所有项目的列表。 🌐 This command retrieves and displays a list of all projects hosted on your Strapi Cloud account. ## strapi 登出 {#strapi-logout} 🌐 strapi logout **别名:** `strapi cloud:logout` 退出 Strapi Cloud。 🌐 Log out of Strapi Cloud. ```bash strapi logout ``` 此命令会将你从 Strapi Cloud 登出。一旦运行 `logout` 命令,浏览器页面将会打开,终端将显示你已成功登出的确认信息。你将无法再使用 `deploy` 命令。 🌐 This command logs you out of Strapi Cloud. Once the `logout` command is run, a browser page will open and the terminal will display a confirmation message that you were successfully logged out. You will not be able to use the `deploy` command anymore. # 缓存与性能 {#caching--performance} Source: https://docs.strapi.io/cloud/getting-started/caching # 缓存与性能 {#caching--performance} 🌐 Caching & Performance 对于具有大量可缓存内容(如图片、视频和其他静态资源)的 Strapi Cloud 应用,通过 # Strapi 云基础 {#strapi-cloud-fundamentals} Source: https://docs.strapi.io/cloud/getting-started/cloud-fundamentals # Strapi 云基础 {#strapi-cloud-fundamentals} 🌐 Strapi Cloud fundamentals 在进一步阅读此 Strapi Cloud 文档之前,我们建议你先了解以下主要概念。它们将帮助你理解 Strapi Cloud 的工作原理,并确保顺利使用 Strapi Cloud。 🌐 Before going any further into this Strapi Cloud documentation, we recommend you to acknowledge the main concepts below. They will help you to understand how Strapi Cloud works, and ensure a smooth Strapi Cloud experience. - **托管平台**
Strapi Cloud 是一个托管平台,可用于部署已经使用 Strapi CMS(内容管理系统)创建的现有 Strapi 项目。Strapi Cloud *不是* Strapi CMS 的 SaaS()版本,而应被视为 PaaS()。如需了解有关 Strapi CMS 的更多信息,请随时参考 [CMS 文档](https://strapi.nodejs.cn/cms/intro)。 - **Strapi Cloud 定价方案**
作为 Strapi Cloud 用户,你可以在 4 种方案中进行选择:免费版、基础版、专业版和企业版。根据不同的方案,你可以访问不同的功能、支持和自定义选项(更多详细信息请参见 [定价页面](https://strapi.io/pricing-cloud))。在本 Strapi Cloud 文档中, 、 和 标签可以显示在章节标题下方,以表示该功能仅从对应的付费方案开始可用。如果未显示任何标签,则该功能在免费版中也可用。 - **Strapi Cloud 用户类型**
在 Strapi Cloud 项目中可以有两种类型的用户:所有者和维护者。所有者是创建项目的人,因此可以访问该项目的所有功能和选项。维护者是被项目所有者邀请来为已创建的项目做出贡献的用户。正如[协作](/cloud/projects/collaboration)页面所述,维护者无法查看和访问 Strapi Cloud 仪表板中的所有功能和选项。 - **支持**
Strapi 支持团队提供的支持级别取决于你订阅的 Strapi Cloud 计划。免费计划不包括访问支持。Essential 和 Pro 计划包含基础支持,而 Scale 计划包含标准支持。有关支持级别的所有详细信息,请参阅[专门的支持文章](https://support.strapi.io/support/solutions/articles/67000680833-what-is-supported-by-the-strapi-team#Not-Supported)。 - **Strapi Cloud 与自托管环境中的 API 访问**
REST 和 GraphQL API 在 Strapi Cloud 和自托管服务器上的表现是相同的。唯一的区别是 URL: - 基础 API 域:在 Strapi Cloud 上,你的 API 使用环境的域(例如 `https://.strapiapp.com/api/...`),或者如果你设置了自定义域,则使用你的自定义域(参见 [域文档](/cloud/projects/settings#domains))。自托管项目将使用你所暴露的任何域。 - 媒体库网址:来自 Strapi Cloud 的 REST 和 GraphQL 响应中的媒体字段始终使用项目媒体域(例如 `.media.strapiapp.com`),即使你通过自定义域访问 API。自托管项目会返回配置的上传提供商的 URL,因此域名可以与你自己的网站或 CDN 匹配。当你将项目从自托管迁移到 Strapi Cloud 时,请确保你的前端读取 API 返回的绝对 URL 或接受 Strapi Cloud 的媒体域。 # Strapi 云端 - 仪表板部署 Source: https://docs.strapi.io/cloud/getting-started/deployment # 使用云仪表板进行项目部署 {#project-deployment-with-the-cloud-dashboard} 🌐 Project deployment with the Cloud dashboard 这是一个使用云仪表板首次在 Strapi Cloud 部署你的项目的逐步指南。 🌐 This is a step-by-step guide for deploying your project on Strapi Cloud for the first time, using the Cloud dashboard. :::prerequisites 在你可以使用 Cloud 仪表板将 Strapi 应用部署到 Strapi Cloud 之前,你需要具备以下先决条件: 🌐 Before you can deploy your Strapi application on Strapi Cloud using the Cloud dashboard, you need to have the following prerequisites: * Strapi 版本 `4.8.2` 或更高 * 项目数据库必须与 PostgreSQL 兼容。Strapi 不支持也不推荐使用任何外部数据库,尽管可以配置一个(参见 [高级数据库配置](/cloud/advanced/database))。 * 项目源代码托管在 5. 设置你的 Strapi Cloud 项目。 5.a. 填写以下信息: | 设置名称 | 说明 ||--------------|--------------------------------------------------------------------------------------------------|| 显示名称 | 名称会根据你选择的仓库自动填充,但你可以根据需要编辑它。 || Git 分支 | 从下拉菜单中选择你想要部署的分支。 || 推送时部署 | 勾选此框将在向所选分支推送更改时自动触发部署。禁用时,你需要手动部署最新的更改。 || 地区 | 选择托管你的 Strapi 应用的服务器地理位置。可选地区包括美国(东部)、欧洲(西部)或亚洲(东南部)。 | :::note Git 分支和“在推送时部署”设置可以随后通过项目设置进行修改。然而,托管区域只能在创建项目时选择(参见 [项目设置](/cloud/projects/settings))。 ::: 5.b.(可选)点击 **显示高级设置** 来填写以下选项: | Setting name | Instructions | |--------------|---------------------------------------------------------------------------------------------------------| | Base directory | Write the name of the directory where your Strapi app is located in the repository. This is useful if you have multiple Strapi apps in the same repository or if you have a monorepo. | | Environment variables | Click on **Add variable** to add environment variables used to configure your Strapi app (see [Environment variables](/cms/configurations/environment/) for more information). You can also add environment variables to your Strapi application by adding a `.env` file to the root of your Strapi app directory. The environment variables defined in the `.env` file will be used by Strapi Cloud. | | Node version | Choose a Node version from the drop-down. The default Node version will automatically be chosen to best match the version of your Strapi project. If you manually choose a version that doesn't match with your Strapi project, the build will fail but the explanation will be displayed in the build logs. | :::strapi Using Environment Variables 你可以使用环境变量将你的项目连接到外部数据库,而不是 Strapi Cloud 使用的默认数据库(更多详情请参见 [数据库配置](/cms/configurations/database#environment-variables-in-database-configurations))。如果你想回退并再次使用 Strapi 的默认数据库,请删除你的 `DATABASE_` 环境变量(不涉及自动迁移)。 你也可以在这里设置自定义电子邮件提供商。Sendgrid 被设置为在 Strapi Cloud 上托管的 Strapi 应用的默认提供商(更多详情请参见 [providers configuration](/cms/features/email#providers))。 ::: ## 设置账单详情 {#setting-up-billing-details} 🌐 Setting up billing details :::strapi No billing step for the Free plan 如果你选择免费计划,此结算步骤将被跳过,因为在创建项目时你不会被要求提供信用卡信息。 🌐 If you chose the free plan, this billing step will be skipped as you will not be asked to share your credit card details at the creation of the project. 跳到下面部分的第5步以完成项目创建。 ::: 1. 点击 **继续到付款** 按钮。你将被重定向到付款页面,在那里你可以输入你的付款信息并查看你的发票。 2. 在*付款方式*部分,添加一张信用卡。此卡将用于所有与项目相关的事务,包括附加项目和超额费用。 3. 在*账单信息*部分,填写你的付款信息和账单地址。 4. 查看*发票*部分。购买月度订阅时,订阅价格将按当前计费周期剩余天数按比例计算。也可以展开*折扣码*部分以输入代码。 :::note 根据你的账单地址,可能会在你的发票上加收税费: - 在欧盟和英国,提供有效的增值税编号可免除增值税。如果未提供有效的增值税编号,增值税将被添加到你的发票中。 - 在美国,适用的销售税是根据你的州和地址计算的。 ::: 5. 点击 **订阅** 按钮以完成新 Strapi Cloud 项目的创建。 ## 部署你的项目 {#deploying-your-project} 🌐 Deploying your project 确认项目创建后,你将被重定向到你的*项目仪表板*,在这里你将能够跟踪其创建和首次部署。 🌐 After confirming the project creation, you will be redirected to your *Project dashboard* where you will be able to follow its creation and first deployment. 在你的项目部署时,你 already 可以开始配置一些 [项目设置](/cloud/projects/settings)。 🌐 While your project is deploying, you can already start configuring some of your [project settings](/cloud/projects/settings). :::note 如果在项目创建过程中发生错误,进度指示器将停止并显示错误消息。你将在失败步骤旁看到一个**重试**按钮,允许你重新启动创建过程。 🌐 If an error occurs during the project creation, the progress indicator will stop and display an error message. You will see a **Retry** button next to the failed step, allowing you to restart the creation process. ::: 一旦你的项目成功部署,创建跟踪器将被你的部署列表取代,你将能够访问你的云托管项目。不要忘记在分享你的 Strapi 项目之前创建第一个管理员用户。 🌐 Once your project is successfully deployed, the creation tracker will be replaced by your deployments list and you will be able to visit your Cloud hosted project. Don't forget to create the first Admin user before sharing your Strapi project. ## 接下来做什么? {#icon-namefast-forward--what-to-do-next} 现在你已经通过云控制面板部署了项目,我们鼓励你探索以下想法,以获得更完整的 Strapi 云体验: 🌐 Now that you have deployed your project via the Cloud dashboard, we encourage you to explore the following ideas to have an even more complete Strapi Cloud experience: - 邀请其他用户[协作你的项目](/cloud/projects/collaboration)。 - 查看 [部署管理文档](/cloud/projects/deploys) 以了解如何为你的项目触发新的部署。 # Strapi 云端 - CLI 部署 Source: https://docs.strapi.io/cloud/getting-started/deployment-cli # 使用命令行接口 (CLI) 进行项目部署 {#project-deployment-with-the-command-line-interface-cli} 🌐 Project deployment with the Command Line Interface (CLI) 这是一个逐步指南,教你如何首次使用命令行接口在 Strapi Cloud 上部署你的项目。 🌐 This is a step-by-step guide for deploying your project on Strapi Cloud for the first time, using the Command Line Interface. :::prerequisites 在使用命令行接口将你的 Strapi 应用部署到 Strapi Cloud 之前,你需要具备以下先决条件: 🌐 Before you can deploy your Strapi application on Strapi Cloud using the Command Line Interface, you need to have the following prerequisites: - 拥有一个 Google、GitHub 或 GitLab 账号。 - 拥有一个已创建的 Strapi 项目(参见 CMS 文档中的 [从 CLI 安装](/cms/installation/cli)),存储在本地。项目必须小于 100MB。 - 确保你的硬盘中有可用存储空间,用于存放操作系统的临时文件夹。 ::: ## 登录 Strapi 云 {#logging-in-to-strapi-cloud} 🌐 Logging in to Strapi Cloud 1. 打开你的终端。 2. 导航到存储在本地电脑上的 Strapi 项目的文件夹。 3. 输入以下命令以登录 Strapi Cloud: 4. 在自动打开的浏览器窗口中,确认显示的代码与终端消息中写的代码相同。 5. 仍然在浏览器窗口中,选择通过 Google、GitHub 或 GitLab 登录。窗口应在不久后确认登录成功。 ## 部署你的项目 {#deploying-your-project} 🌐 Deploying your project 1. 在你的终端中,仍然在你的 Strapi 项目文件夹中,输入以下命令来部署项目: 2. 在终端中关注进度条,直到确认项目已成功使用 Strapi Cloud 部署。部署项目将会在免费计划下创建一个新的 Strapi Cloud 项目。 ### 自动部署后续更改 {#automatically-deploying-subsequent-changes} 🌐 Automatically deploying subsequent changes 默认情况下,当使用 Cloud CLI 创建和部署项目时,每次进行更改后,都需要通过运行相应的 `deploy` 命令手动再次部署所有后续更改。 🌐 By default, when creating and deploying a project with the Cloud CLI, you need to manually deploy again all subsequent changes by running the corresponding `deploy` command everytime you make a change. 另一种选择是通过 git 仓库启用自动部署。操作步骤如下: 🌐 Another option is to enable automatic deployment through a git repository. To do so: 1. 将你的代码托管在 git 仓库上,例如 或 。 2. 将你的 Strapi Cloud 项目连接到仓库(请参阅 [项目设置 > 常规](/cloud/projects/settings#general) 中的 _已连接仓库_ 设置)。 3. 仍然在 _项目设置 > 常规_ 选项卡中,勾选“在每次推送到此分支的提交时部署项目”设置框。从现在起,每当提交推送到已连接的 Git 仓库时,都会触发一次新的 Strapi Cloud 部署。 :::note 自动部署与所有其他部署方法兼容,因此一旦连接了 git 仓库,你可以从 [Cloud 仪表板](/cloud/projects/deploys)、[CLI](/cloud/cli/cloud-cli#strapi-deploy) 或通过向已连接的仓库推送新提交来触发对 Strapi Cloud 的新部署。 🌐 Automatic deployment is compatible with all other deployment methods, so once a git repository is connected, you can trigger a new deployment to Strapi Cloud [from the Cloud dashboard](/cloud/projects/deploys), [from the CLI](/cloud/cli/cloud-cli#strapi-deploy), or by pushing new commits to your connected repository. ::: ## ⏩ 接下来做什么? {#-what-to-do-next} 🌐 ⏩ What to do next? 既然你已经通过命令行接口部署了项目,我们鼓励你探索以下想法,以获得更完整的 Strapi Cloud 体验: 🌐 Now that you have deployed your project via the Command Line Interface, we encourage you to explore the following ideas to have an even more complete Strapi Cloud experience: - 访问 Cloud 仪表板以查看你 Strapi 项目的[有用指标和信息](/cloud/projects/overview)。 - 请查看完整的 [命令行接口文档](/cloud/cli/cloud-cli) 以了解其他可用命令。 # 项目部署 Source: https://docs.strapi.io/cloud/getting-started/deployment-options # 使用 Strapi Cloud 部署项目 {#project-deployment-with-strapi-cloud} 🌐 Project deployment with Strapi Cloud 你有两种选择可以使用 Strapi Cloud 部署你的项目: 🌐 You have 2 options to deploy your project with Strapi Cloud: - 要么通过用户界面(UI),这意味着你将直接在 Strapi Cloud 仪表板上执行所有操作, - 或者使用云评论命令行接口(CLI),这意味着你将只与终端进行交互。 下面的指南将引导你完成每种部署选项的所有步骤。 🌐 The guides below will guide you through all the steps for each of the deployment options. # 欢迎使用 Strapi Cloud 文档! {#welcome-to-the-strapi-cloud-documentation} Source: https://docs.strapi.io/cloud/getting-started/intro # 欢迎使用 Strapi Cloud 文档! {#welcome-to-the-strapi-cloud-documentation} 🌐 Welcome to the Strapi Cloud Documentation! Strapi Cloud 文档包含与你的 Strapi Cloud 账户和应用的设置、部署、更新和自定义相关的所有信息。 🌐 The Strapi Cloud documentation contains all information related to the setup, deployment, update and customization of your Strapi Cloud account and applications. :::strapi What is Strapi Cloud? 构建在开源无头 CMS Strapi 之上。 ::: :::prerequisites Strapi 团队推荐的典型工作流程是: 🌐 The typical workflow, which is recommended by the Strapi team, is: 1. 在本地创建你的 Strapi 应用(版本 4.8.2 或更高)。 2. 可以选择通过插件或自定义代码扩展应用。 3. 通过你的 git 提供商(GitHub 或 GitLab)对应用的代码库进行版本控制。 4. 使用 Strapi Cloud 部署应用。 ::: Strapi Cloud 文档按主题组织,顺序应与你使用产品的流程相对应。以下卡片,你可以点击,将重定向到主要主题和步骤。 🌐 The Strapi Cloud documentation is organised in topics in a order that should correspond to your journey with the product. The following cards, on which you can click, will redirect you to the main topics and steps. :::strapi Welcome to the Strapi community! Strapi Cloud 构建在 Strapi 之上,Strapi 是一个开源的、以社区为导向的项目。Strapi 团队秉持着分享他们的愿景,并与 Strapi 社区共同打造 Strapi 的未来。这就是为什么 是开放的:因为所有的见解都非常重要,并将帮助引导项目朝着正确的方向发展。任何社区成员都非常欢迎在这里分享想法和意见。 你也可以加入 、 和 ,并从Strapi社区整体多年来的经验、知识和贡献中受益。 ::: # 账单和使用信息 {#information-on-billing--usage} Source: https://docs.strapi.io/cloud/getting-started/usage-billing # 账单和使用信息 {#information-on-billing--usage} 🌐 Information on billing & usage 此页面包含与你的 Strapi Cloud 账户和项目的使用及计费相关的一般信息。 🌐 This page contains general information related to the usage and billing of your Strapi Cloud account and projects. Strapi Cloud 提供 1 个免费计划和 3 个付费计划:Essential、Pro 和 Scale(见 [定价页面](https://strapi.io/pricing-cloud))。下表总结了 Strapi Cloud 基于使用量的定价计划,涵盖一般功能和使用情况: 🌐 Strapi Cloud offers 1 Free plan and 3 paid plans: Essential, Pro and Scale (see [Pricing page](https://strapi.io/pricing-cloud)). The table below summarizes Strapi Cloud usage-based pricing plans, for general features and usage: | 功能 | 免费 | 基础版 | 专业版 | 企业版 || --- | --- | --- | --- | --- || **数据库条目** | 500 | 无限* | 无限* | 无限* || **资源存储** | 10GB | 50GB | 250GB | 1,000GB || **资源带宽(每月)** | 10GB | 50GB | 500GB | 1,000GB || **API 请求(每月)** | 2,500 | 50,000 | 1,000,000 | 10,000,000 || | | | | || **备份** | 不适用 | 不适用 | 每周 | 每日 || **自定义域名** | 不适用 | 包含 | 包含 | 包含 || **环境** | 不适用 | 不适用 | 包含 0 个(最多可增加 99 个) | 包含 1 个(最多可增加 99 个) || **电子邮件(每月)** | 100 | 无限* | 无限* | 无限* | :::strapi Additional information on usage and features - 一般特性与使用方式: - 数据库条目是你的数据库中的条目数量。 - 资源存储是你的资源所使用的存储量。 - 资源带宽是你的资源所使用的带宽量。 - API 请求是对你的 API 发出的请求数量。这包括对 GraphQL 和 REST API 的请求,但不包括计入 CDN 带宽和存储的文件和媒体资源请求。所有 API 请求都计入你的每月使用量,无论响应类型如何。 - 云特定功能: - 备份指的是 Strapi Cloud 项目的自动备份(有关此功能的更多信息,请参见 [备份文档](/cloud/projects/settings#backups))。 - 自定义域名是指为你的 Strapi 云定义自定义域名的能力(参见 [自定义域名](/cloud/projects/settings#connecting-a-custom-domain))。 - 环境是指计划中包含的环境数量,除默认的生产环境之外(有关该功能的更多信息,请参见[环境](/cloud/projects/settings#environments)文档)。 ::: :::caution The Free Plan is for personal, non-commercial use only 商业用途是指任何为了经济利益而进行的项目,包括: 🌐 Commercial use means any project made for financial gain, including: - 在你的网站上接受或处理付款 - 接受或收取创建、更新或托管网站的付款 - 广告、推广或销售产品或服务 - 为任何第三方托管或投放广告 欲了解更多信息,请访问 [Strapi Cloud-法律](https://strapi.io/cloud-legal) ::: :::info Scale-to-zero and cold start on the Free plan 在免费计划中,项目在短时间不活跃后会自动缩减到零。当应用再次被访问时——无论是通过前端还是通过 API 请求——返回响应可能需要几秒钟(最长可达一分钟)。 升级到付费计划将禁用缩减到零和冷启动,从而始终实现即时响应时间。 🌐 On the Free plan, projects automatically scale down to zero after a short period of inactivity. When the application is accessed again—either through the frontend or via an API request—it may take a few seconds (up to a minute) before a response is returned. Upgrading to a paid plan disables scaling to zero and cold starts, resulting in instant response times at all times. ::: ## 环境管理 {#environments-management} 🌐 Environments management 环境是你的 Strapi Cloud 项目的隔离实例。所有项目都有一个默认的生产环境,但对于 Pro 或 Scale 计划的项目,可以从项目设置的 *环境* 标签中配置其他额外环境(请参见 [Environments](/cloud/projects/settings#environments))。Strapi Cloud 项目可以配置的额外环境数量没有限制。 🌐 Environments are isolated instances of your Strapi Cloud project. All projects have a default production environment, but other additional environments can be configured for projects on a Pro or Scale plan, from the *Environments* tab of the project settings (see [Environments](/cloud/projects/settings#environments)). There is no limit to the number of additional environments that can be configured for a Strapi Cloud project. 额外环境的使用限制与项目的生产环境相同(例如,Pro 计划中的额外环境在资源存储上将限制为 250GB,超出部分将按照与生产环境相同的方式收费)。但请注意,资源带宽和 API 调用是基于项目的,而不是基于环境的,因此即使有额外环境,这些使用限制也不会改变。 🌐 The usage limits of additional environments are the same as for the project's production environment (e.g. an additional environment on the Pro plan will be limited at 250GB for asset storage, and overages will be charged the same way as for the production environment). Note however that the asset bandwidth and API calls are project-based, not environment-based, so these usage limits do not change even with additional environments. ## 账单 {#billing} 🌐 Billing 计费基于你 Strapi Cloud 项目的使用情况。项目计划和附加组件会根据你的计费周期按月或按年计费,而超额部分按月计费。你可以在项目设置的*计费与使用情况*部分查看你的使用和计费信息。 🌐 Billing is based on the usage of your Strapi Cloud projects. Project plans and addons are either billed monthly or yearly, depending on your billing cycle, while overages are billed monthly. You can view your usage and billing information in the *Billing & Usage* section of your project settings. ### 税收 {#taxes} 🌐 Taxes 对于美国、英国和欧盟的账单地址,本地税费可能会被加到你的发票上。税额根据你的账单地址和增值税/税务识别号状态计算,并在结账时和发票上显示。 🌐 For billing addresses in the US, UK and EU, local taxes may be added to your invoices. Tax amounts are calculated based on your billing address and VAT/Tax ID status, and are displayed during checkout and on invoices. 你可以在你的 [账户账单](/cloud/account/account-billing) 设置中添加或更新你的增值税/税号。 🌐 You can add or update your VAT/Tax ID from your [Account Billing](/cloud/account/account-billing) settings. ### 超额 {#overages} 🌐 Overages :::caution 免费计划不允许超额使用。 🌐 Overages are not allowed on the Free plan. ::: 如果你超出了 API 请求、资源带宽或资源存储的计划限制,你将被收取相应的超额费用。 🌐 If you exceed the limits of your plan for API Requests, Asset Bandwidth, or Asset Storage, you will be charged for the corresponding overages. 例如,如果你在专业版计划的资源带宽中超过 500GB 的限制,超出部分将在当前计费周期结束时或项目删除时收费。超额部分不按比例计算,将全额收费。 🌐 For example, if you exceed the 500GB limit in asset bandwidth of the Pro plan, you will be charged for the excess bandwidth at the end of the current billing period or on project deletion. Overages are not prorated and are charged in full. 超出部分按月收费,费率如下: 🌐 Overages are charged monthly, according to the following rates: | 功能 | 价格 || --- | --- || **API 请求** | $1.50 / 25,000 次请求 || **资源带宽** | $30.00 / 100GB || **资源存储** | $0.60 / GB 每月 | ### 项目暂停 {#project-suspension} 🌐 Project suspension 项目可能会因各种原因进入**暂停**状态,包括:未付款的发票、超出免费计划的限制,或违反 Strapi Cloud 的 。 如果你的项目被暂停,你将无法再访问 Strapi 管理面板,也无法触发新的部署。你的项目仪表板上将会显示一个横幅,说明暂停的原因。你也会收到电子邮件通知。 🌐 If your project is suspended, you will no longer be able to access the Strapi admin panel, nor trigger new deployments. A banner will appear in your project's dashboard, indicating the cause of the suspension. You will also be notified by email. #### 由于超出免费计划限制而暂停项目 {#project-suspension-for-exceeding-the-free-plan-limits} 🌐 Project suspension for exceeding the Free plan limits 当使用免费计划托管的项目超过 API 请求或资源带宽限制时,该项目将被暂停,直到下个月初每月配额重置。 🌐 When a project hosted with the Free plan exceeds either the API requests or the Asset Bandwidth limits, it will be suspended until the monthly allowance resets at the beginning of the following month. 在项目暂停期间: 🌐 While the project is suspended: - 用户无法触发新的部署 - 无法访问该应用 - 用户无法更改项目的设置 要立即重新激活该项目,用户可以升级到付费计划。 🌐 To reactivate the project immediately, users can upgrade to a paid plan. #### 由于账单问题项目暂停 {#project-suspension-due-to-billing-issues} 🌐 Project suspension due to billing issues 如果你有未支付的发票,你的项目订阅将会自动被取消,项目将会被暂停。 🌐 If you have unpaid invoices, the subscription of your project will automatically be canceled and the project suspended. 要重新激活你项目的订阅,请前往 *设置 > 账单与使用情况* 并点击 **重新激活订阅** 按钮。 🌐 To reactivate your project's subscription, head to *Settings > Billing & Usage* and click on the **Reactivate subscription** button. :::warning 如果你在30天内不解决该问题,你的暂停项目将被删除,所有数据将永久丢失。 🌐 If you do not resolve the issue within 30 days, your suspended project will be deleted and all its data will be permanently lost. ::: #### 因其他原因暂停项目 {#project-suspension-for-other-reasons} 🌐 Project suspension for other reasons 如果你的项目因非未支付发票导致订阅取消的原因而被暂停,你可能无法自行重新激活项目。你应该会收到一封包含解决问题说明的电子邮件。如果你没有收到电子邮件通知,请联系 [Strapi 支持](mailto:support@strapi.io)。 🌐 If your project was suspended for reasons other than unpaid invoice leading to subscription cancellation, you may not have the possibility to reactivate your project yourself. You should receive an email with instructions on how to resolve the issue. If you do not receive the email notification, please contact [Strapi Support](mailto:support@strapi.io). ### 取消订阅 {#subscription-cancellation} 🌐 Subscription cancellation 如果你想取消你的 Strapi Cloud 订阅,你有两种选择: 🌐 If you want to cancel your Strapi Cloud subscription, you have 2 options: - 要么将你的项目订阅更改为免费计划(请参阅 [降级到其他计划](/cloud/projects/settings#downgrading-to-another-plan) 文档), - 或完全删除你的项目(请参见[删除 Strapi Cloud 项目](/cloud/projects/settings#deleting-a-strapi-cloud-project) 文档)。 # 合作 Source: https://docs.strapi.io/cloud/projects/collaboration # 项目合作 {#collaboration-on-projects} 🌐 Collaboration on projects 项目由用户通过他们的 Strapi Cloud 账户创建。Strapi Cloud 用户可以将他们的项目分享给任何其他人,因此这些新用户可以访问项目仪表板并在该项目上进行协作,而项目拥有者无需分享他们的凭据。 🌐 Projects are created by a user via their Strapi Cloud account. Strapi Cloud users can share their projects to anyone else, so these new users can have access to the project dashboard and collaborate on that project, without the project owner to ever have to share their credentials. 被邀请协作项目的用户,称为维护者,不具有与项目所有者相同的权限。与项目所有者相反,维护者: 🌐 Users invited to collaborate on a project, called maintainers, do not have the same permissions as the project owner. Contrary to the project owner, maintainers: - 不能自己将项目分享给他人 - 无法从项目设置中删除项目 - 无法访问项目设置的*计费*部分 ## 共享项目 {#sharing-a-project} 🌐 Sharing a project 邀请新的维护者参与项目合作: 🌐 To invite a new maintainer to collaborate on a project: 1. 在*项目*页面上,点击你选择的项目即可跳转到其仪表板。 2. 点击位于仪表板页眉的**分享**按钮。 3. 在 *共享 [项目名称]* 对话框中,在文本框中输入要邀请的人的电子邮件地址。应出现一个下拉菜单,显示“邀请 [电子邮件地址]”。 4. 点击下拉菜单:电子邮件地址应显示在文本框正下方的紫色框中。 5. (可选) 重复步骤3和4以邀请更多人。电子邮件地址只能逐一输入,但邀请可以同时发送给多个电子邮件地址。 6. 点击 **发送** 按钮。 新维护者将收到一封电子邮件,其中包含一个链接,点击该链接即可加入项目。一旦项目被共享,代表维护者的头像将显示在项目仪表板的标题栏中,位于 **共享** 按钮旁边,以查看有多少维护者在该项目上协作以及他们是谁。 🌐 New maintainers will be sent an email containing a link to click on to join the project. Once a project is shared, avatars representing the maintainers will be displayed in the project dashboard's header, next to the **Share** button, to see how many maintainers collaborate on that project and who they are. :::tip 头像使用 GitHub、Google 或 GitLab 的个人资料图片,但对于待审核用户,只有在维护者账户激活之前显示首字母。你可以将鼠标悬停在头像上以显示维护者的全名。 🌐 Avatars use GitHub, Google or GitLab profile pictures, but for pending users only initials will be displayed until the activation of the maintainer account. You can hover over an avatar to display the full name of the maintainer. ::: ## 管理维护者 {#managing-maintainers} 🌐 Managing maintainers 在通过点击项目仪表板的**共享**按钮可访问的*共享 [项目名称]* 对话框中,项目所有者可以查看已被邀请参与项目协作的维护者完整列表。在那里,可以查看每个维护者的当前状态并对其进行管理。 🌐 From the *Share [project name]* dialog accessible by clicking on the **Share** button of a project dashboard, projects owners can view the full list of maintainers who have been invited to collaborate on the project. From there, it is possible to see the current status of each maintainer and to manage them. 显示全名的维护者是指那些在收到邀请邮件后激活了账户的用户。然而,如果列表中显示的是电子邮件地址的维护者,这意味着他们尚未激活账户,因此无法访问项目仪表板。在这种情况下,应在电子邮件地址旁边标明状态以解释问题: 🌐 Maintainers whose full name is displayed are users who did activate their account following the invitation email. If however there are maintainers in the list whose email address is displayed, it means they haven't activated their accounts and can't access the project dashboard yet. In that case, a status should be indicated right next to the email address to explain the issue: - 待处理:邀请邮件已发送,但维护者尚未采取行动。 - 已过期:电子邮件已在 72 小时前发送,邀请已过期。 对于已过期的状态,可以通过点击 **管理** 按钮,然后选择 **重新发送邀请** 来发送另一封邀请邮件。 🌐 For Expired statuses, it is possible to send another invitation email by clicking on the **Manage** button, then **Resend invite**. ### 撤销维护者权限 {#revoking-maintainers} 🌐 Revoking maintainers 撤销维护者对项目仪表板的访问权限: 🌐 To revoke a maintainer's access to the project dashboard: 1. 点击项目仪表板标题中的 **分享** 按钮。 2. 在“*有权限的人*”列表中,找到要撤销访问权限的维护者,然后点击**管理**按钮。 3. 点击 **撤销** 按钮。 4. 在确认对话框中,再次点击 **撤销** 按钮。 被撤销的维护者将完全无法访问项目仪表板。 🌐 The revoked maintainer will completely stop having access to the project dashboard. :::note 被撤销项目访问权限的维护者不会收到任何电子邮件或通知。 🌐 Maintainers whose access to the project has been revoked do not receive any email or notification. ::: # 部署管理 Source: https://docs.strapi.io/cloud/projects/deploys # 部署管理 {#deployments-management} 🌐 Deployments management 创建一个新的 Strapi Cloud 项目会自动触发该项目的部署。之后,部署可以是: 🌐 The creation of a new Strapi Cloud project automatically trigger the deployment of that project. After that, deployments can be: - 在需要时手动触发,[从云仪表板](#triggering-a-new-deployment)或[从命令行接口](/cloud/cli/cloud-cli#strapi-deploy), - 或者每次向分支推送新提交时自动触发,如果 Strapi Cloud 项目已连接到 git 仓库并且启用了“推送时部署”选项(参见 [项目设置](/cloud/projects/settings#modifying-git-repository--branch))。 如果需要,正在进行的部署也可以[手动取消](#cancelling-a-deployment)。 🌐 Ongoing deployments can also be [manually canceled](#cancelling-a-deployment) if needed. ## 触发新的部署 {#triggering-a-new-deployment} 🌐 Triggering a new deployment 要手动触发项目的新部署,请点击项目仪表板标题右上角始终显示的**触发部署**按钮。此操作将在*部署*标签中添加一个新卡片,你可以在其中监控状态并实时查看部署日志(参见[部署历史和日志](/cloud/projects/deploys-history))。 🌐 To manually trigger a new deployment for your project, click on the **Trigger deployment** button always displayed in the right corner of a project dashboard's header. This action will add a new card in the *Deployments* tab, where you can monitor the status and view the deployment logs live (see [Deploy history and logs](/cloud/projects/deploys-history)). ## 取消部署 {#cancelling-a-deployment} 🌐 Cancelling a deployment 如果出于任何原因你想取消正在进行且未完成的部署: 🌐 If for any reason you want to cancel an ongoing and unfinished deployment: 1. 转到最新触发的部署的*部署详细信息*页面(参见[访问日志详情](/cloud/projects/deploys-history#accessing-deployment-details--logs))。 2. 点击右上角的 **取消部署** 按钮。部署的状态将自动更改为 *已取消*。 :::tip 你也可以从列出部署历史的 *Deployments* 标签中取消部署。处于 *Building* 状态的正在进行的部署卡片将显示一个 ![取消按钮](/img/assets/icons/clear.svg) 按钮,用于取消部署。 🌐 You can also cancel a deployment from the *Deployments* tab which lists the deployments history. The card of ongoing deployment with the *Building* status will display a ![Cancel button](/img/assets/icons/clear.svg) button for cancelling the deployment. ::: # 部署历史和日志 Source: https://docs.strapi.io/cloud/projects/deploys-history # 部署历史和日志 {#deploy-history-and-logs} 🌐 Deployment history and logs 对于每个 Strapi Cloud 项目,你可以访问所有已发生部署的历史记录及其详细信息,包括构建和部署日志。此信息可在 *部署* 选项卡中查看。 🌐 For each Strapi Cloud project, you can access the history of all deployments that occurred and their details including build and deployment logs. This information is available in the *Deployments* tab. ## 查看部署历史记录 {#viewing-deploy-history} 🌐 Viewing the deployment history 在*部署*选项卡中显示了按时间顺序排列的卡片列表,其中包含你项目的所有历史部署的详细信息。 🌐 In the *Deployments* tab is displayed a chronological list of cards with the details of all historical deployments for your project. ,带有指向你的 git 提供者的直接链接,以及提交信息 - 部署状态: - *部署* - *完成* - *已取消* - *构建失败* - *部署失败* - 上次部署时间(部署触发时间及持续时间) - 分支 ## 访问部署详情和日志 {#accessing-deployment-details--logs} 🌐 Accessing deployment details & logs 在 *Deployments* 标签页中,你可以将鼠标悬停在部署卡片上,使 ![查看日志按钮](/img/assets/icons/Eye.svg) **显示详情** 按钮出现。点击此按钮将重定向到包含部署详细日志的 *Deployment details* 页面。 🌐 From the *Deployments* tab, you can hover a deployment card to make the ![See logs button](/img/assets/icons/Eye.svg) **Show details** button appear. Clicking on this button will redirect you to the *Deployment details* page which contains the deployment's detailed logs. ,并提供指向你的 git 提供者的直接链接,以及用于此部署的提交信息 - *状态*,可以是 *构建中*、*部署中*、*完成*、*已取消*、*构建失败* 或 *部署失败* - *来源*: 此次部署的分支和提交信息 - *持续时间*:部署所花费的时间以及发生的时间 # 通知 Source: https://docs.strapi.io/cloud/projects/notifications # 通知 {#notifications} 🌐 Notifications 可以通过点击云仪表板顶部导航中的铃铛图标 来打开通知中心。 它显示你所有现有项目的最新通知列表。点击列表中的通知卡片将重定向到对应部署的*日志详情*页面(更多信息请参见[部署历史与日志](/cloud/projects/deploys-history#accessing-deployment-details--logs))。 🌐 It displays a list of the latest notifications for all your existing projects. Clicking on a notification card from the list will redirect you to the *Log details* page of the corresponding deployment (more information in [Deploy history & logs](/cloud/projects/deploys-history#accessing-deployment-details--logs)). 以下通知可以在通知中心列出: 🌐 The following notifications can be listed in the Notifications center: - *部署完成*:当部署成功完成时。 - *构建失败*:当部署在构建阶段失败时。 - *部署失败*:当部署阶段的部署失败时。 - *已触发部署*:当连接的仓库有新的推送时,会触发部署。然而,当部署是手动触发时,该通知不会发送。 :::note 所有超过30天的通知将自动从通知中心移除。 🌐 All notifications older than 30 days are automatically removed from the Notification center. ::: # 项目概览 Source: https://docs.strapi.io/cloud/projects/overview # 项目概览 {#projects-overview} 🌐 Projects overview *项目* 页面显示你所有 Strapi Cloud 项目的列表。在这里,你可以管理你的项目并访问相应的应用。 🌐 The *Projects* page displays a list of all your Strapi Cloud projects. From here you can manage your projects and access the corresponding applications. 每个项目卡显示以下信息: 🌐 Each project card displays the following information: * 项目名称 * 生产环境上一次成功部署的日期 * 项目的当前状态: * *未连接*,如果项目仓库未连接到 Strapi Cloud * *已暂停*,如果项目已被暂停(请参阅[项目暂停](/cloud/getting-started/usage-billing#project-suspension)以重新激活项目) * *版本不兼容*,如果项目使用的 Strapi 版本与 Strapi Cloud 不兼容 每个项目卡还显示一个 菜单图标,以访问以下选项: * **访问应用**:跳转到应用 * **转到部署**:以跳转到 [*部署*](/cloud/projects/deploys) 页面 * **前往设置**:以被重定向到 [*设置*](/cloud/projects/settings) 页面 :::tip 点击导航栏中的 * 产品更新* 按钮,查看最新发布的功能和修复内容。 ::: ## 访问项目仪表板 {#accessing-a-projects-dashboard} 🌐 Accessing a project's dashboard 在 *项目* 页面,点击任意项目卡片以访问其仪表板。它显示项目和环境的详细信息,并可访问部署历史记录以及所有可用的设置。 🌐 From the *Projects* page, click on any project card to access its dashboard. It displays the project and environment details and gives access to the deployment history and all available settings. 在所选项目的仪表板标题中,你可以: 🌐 From the dashboard's header of a chosen project, you can: - 使用 **共享** 按钮邀请用户协作项目(参见 [协作](/cloud/projects/collaboration))并查看已被邀请的用户图标 , - 使用 **设置**按钮访问项目及其现有环境的设置 , - 选择要为项目可视化的环境或添加新环境 , - 触发新的部署(参见 [部署管理](/cloud/projects/deploys))并访问你的应用 。 你的项目仪表板还显示: 🌐 Your project's dashboard also displays: - “*部署*” 和 “*运行日志*” 标签,用于查看部署历史(更多详情请参见 [部署历史和日志](/cloud/projects/deploys-history))以及项目的运行日志(参见 [专用文档页面](/cloud/projects/runtime-logs)) - 界面右侧框中的项目和环境详细信息 ,包括: - API 调用次数, - 资源带宽和存储的当前使用情况, - 分支的名称以及一个 **管理** 按钮,用于重定向到分支设置(参见 [修改 git 仓库和分支](/cloud/projects/settings#modifying-git-repository--branch)), - 基目录的名称, - Strapi 版本号, - Strapi 应用的 URL。 # 运行时日志 Source: https://docs.strapi.io/cloud/projects/runtime-logs # 运行时日志 {#runtime-logs} 🌐 Runtime logs 在选定项目的仪表板中,*运行时日志* 标签显示项目的实时日志。 🌐 From a chosen project's dashboard, the *Runtime logs* tab displays the live logs of the project. :::note - 只有在项目成功部署后,才能访问*运行时日志*。 - 免费的计划中的项目运行时日志不是实时的,并且每次由于不活动而将应用缩放为零时都会被重置。 ::: # 项目设置 Source: https://docs.strapi.io/cloud/projects/settings # 项目设置 {#project-settings} 🌐 Project settings 在所选项目的仪表板中,位于页眉的 **设置**按钮使你能够管理你的 Strapi Cloud 项目及其环境的配置和设置。 界面左侧的设置菜单分为两类:整个项目的设置以及针对项目中配置的任何环境的特定设置。 🌐 The settings' menu on the left side of the interface is separated into 2 categories: the settings for the entire project and the settings specific to any configured environment for the project. ## 项目级设置 {#project-level-settings} 🌐 Project-level settings 项目设置有5个可用的标签页: 🌐 There are 5 tabs available for the project settings: - [*通用*](#general), - [*环境*](#environments), - [*账单与使用*](#billing--usage), - [计划](#plans), - 以及 [发票](#invoices)。 ### 一般 {#general} 🌐 General 项目级设置的 *常规*选项卡使你能够检查和更新项目的以下选项: - *基本信息*,请参见: - 你的 Strapi Cloud 项目的名称——用于在云控制面板、Strapi CLI 和部署 URL 上识别项目——并更改它(参见 [重命名项目](#renaming-project))。 - 你为 Strapi Cloud 项目选择的托管区域,即项目及其数据和资源存储的服务器的地理位置。托管区域在创建项目时设置(参见 [项目创建](/cloud/getting-started/deployment)),之后无法修改。 - 项目的元数据,包括生产应用的内部名称和订阅 ID,这对于调试和支持目的可能很有用。 - *Strapi CMS 许可证密钥*:用于在你的云项目上直接启用和使用某些 CMS 功能(请参阅[定价页面](https://strapi.io/pricing-self-hosted)购买许可证)。 - *已连接的 Git 仓库*:用于更改项目使用的仓库和分支(请参见 [修改 git 仓库与分支](#modifying-git-repository--branch))。还可以启用/禁用“推送时部署”选项。 - *危险区域*,与: - *转移所有权*:项目所有者将云项目的所有权转移给已存在的维护者(参见[转移项目所有权](#transferring-project-ownership))。 - *删除项目*:永久删除你的 Strapi Cloud 项目(参见 [删除 Strapi Cloud 项目](#deleting-a-strapi-cloud-project))。 #### 重命名项目 {#renaming-project} 🌐 Renaming project 项目名称在项目创建时设置(参见 [项目创建](/cloud/getting-started/deployment)),之后可以通过项目设置进行修改。 🌐 The project name is set at project creation (see [Project creation](/cloud/getting-started/deployment)) and can be modified afterwards via the project settings. 1. 在 *常规*选项卡的*基本信息*部分,点击 编辑按钮。 2. 在对话框中,在*项目名称*文本框中写上你选择的新项目名称。 3. 点击 **重命名** 按钮以确认项目名称的修改。 #### 添加 CMS 许可证密钥 {#adding-cms-license-key} 🌐 Adding a CMS license key 可以将 CMS 许可证密钥添加并连接到 Strapi Cloud 项目,以解锁整个项目环境中的额外 Strapi CMS 功能。通过许可证密钥可访问的 CMS 功能取决于所购买的许可证类型。有关更多信息和/或购买许可证,请参阅 。 :::note 如果你没有看到 *Strapi CMS 许可密钥* 部分,这可能意味着你的订阅是旧版订阅,并且不支持自定义 CMS 许可。这意味着你已经拥有一个会自动包含在你的项目中的许可。 🌐 If you don't see the *Strapi CMS license key* section, it probably means that your subscription is a legacy one and does not support custom CMS licenses. It means that you already have one that is automatically included on your project. ::: 1. 在 *Strapi CMS 许可密钥* 部分,点击 **添加许可** 按钮。 2. 在对话框中,将你的许可密钥粘贴到字段中。 3. 点击 **保存并部署** 按钮以使更改生效。 要从你的 Strapi Cloud 项目中移除 Strapi CMS 许可证,你可以点击 **取消关联许可证** 按钮。这也将移除对之前添加的许可证中包含的 CMS 功能的访问和使用权限。 🌐 To remove the Strapi CMS license from your Strapi Cloud project, you can click on the **Unlink license** button. This will also remove access and usage to the CMS features included in the previously added license. :::note 许可证密钥已应用于项目中的所有环境。 🌐 The license key is applied to all the environments in the project. ::: #### 修改 git 仓库和分支 {#modifying-git-repository--branch} 🌐 Modifying git repository & branch Strapi Cloud 项目的 GitHub 或 GitLab 仓库、分支和基础目录默认在创建项目时选择(参见 [创建项目](/cloud/getting-started/deployment))。在项目创建后,可以通过项目设置更新项目仓库或切换到其他 Git 提供商。 🌐 The GitHub or GitLab repository, branch and base directory for a Strapi Cloud project are by default chosen at the creation of the project (see [Creating a project](/cloud/getting-started/deployment)). After the project's creation, via the project settings, it is possible to update the project repository or switch to another git provider. :::caution 更新 git 仓库可能导致项目及其数据的丢失,例如如果选择了错误的仓库或旧仓库与新仓库之间的数据结构不匹配。 🌐 Updating the git repository could result in the loss of the project and its data, for instance if the wrong repository is selected or if the data schema between the old and new repository doesn't match. ::: 1. 在 *常规*选项卡的*已连接的 Git 仓库*部分,点击**更新仓库**按钮。你将被重定向到另一个界面。 2. (可选)如果你希望不仅更新仓库,还想切换到另一个 git 提供商,请点击界面右上角的 **切换 Git 提供商** 按钮。在返回 *更新仓库* 界面之前,你将被重定向到所选 git 提供商的授权设置。 3. 在*更新仓库*部分,填写两个可用的设置: | 设置名称 | 使用说明 || --------------- | ------------------------------------------------------------------------ || 账户 | 从下拉列表中选择一个账户。 || 仓库 | 从下拉列表中选择一个仓库。 | 4. 在 *选择 Git 分支* 部分,为你的任何环境填写可用设置。请注意,每个环境的分支可以通过其自身的设置进行编辑,参见 [常规(环境)](#environments)。 | 设置名称 | 说明 || --------------- | ------------------------------------------------------------------------ || 分支 | 从下拉列表中选择一个分支。 || 基本目录 | 在文本框中填写基本目录的路径。 || 自动部署 | 勾选该框以在向所选分支推送新提交时自动触发新部署。取消勾选以禁用此选项。 | 5. 点击 **保存并部署** 按钮以使更改生效。 #### 转移项目所有权 {#transferring-project-ownership} 🌐 Transferring project ownership Strapi Cloud 项目的所有权可以转让给其他用户,只要他们是该项目的维护者。这可以由当前项目所有者主动发起,也可以由项目维护者提出请求。一旦所有权转让完成,该转让将是永久的,直到新所有者决定再次将所有权转让给另一位维护者。 🌐 The ownership of the Strapi Cloud project can be transferred to another user, as long as they're a maintainer of the project. It can either be at the initiative of the current project owner, or can be requested by a project maintainer. Once the ownership is transferred, it is permanent until the new owner decides to transfer the ownership again to another maintainer. :::prerequisites 要转让项目的所有权,必须满足以下要求: 🌐 For the ownership of a project to be transferred, the following requirements must be met: - 该项目必须使用付费计划,且当前无已过期的卡或未支付的账单。 - 维护者必须已经填写了他们的账单信息。 - 该项目不得有任何现有的所有权转让在进行中。 请注意,当在订阅续订的同一天(即每月的1日)进行所有权转让时,转让可能会失败。如果当天转让失败,但所有先决条件已满足,你应等待几小时后再尝试。 🌐 Note that ownership transfers might fail when done the same day of subscription renewal (i.e. 1st of every month). If the transfer fails that day, but all prerequisites are met, you should wait a few hours and try again. ::: 1. 在 *常规*选项卡的*危险区域*部分,点击**转移所有权**按钮。 2. 在对话中: - 如果你是项目拥有者:通过点击其名字旁的 **...** > **转让所有权** 来选择应被转让所有权的维护者。 - 如果你是维护者:在列表中找到自己,然后点击与你的名字相关的 **...** > **转让所有权**。 3. 在新对话框中点击 **转移所有权** 按钮以确认转移/请求。 一封电子邮件将发送给两位用户。需要转让所有权或继承的人员必须点击电子邮件中的 **确认转让** 按钮。完成后,前所有者将收到一封确认电子邮件,确认转让已成功完成。 🌐 An email will be sent to both users. The person who needs to transfer the ownership or inherit it will have to click on the **Confirm transfer** button in the email. Once done, the previous owner will receive a confirmation email that the transfer has successfully been done. :::tip 只要所有权转移或请求尚未确认,就可以在选择维护者的同一对话框中选择取消。 🌐 As long as the ownership transfer or request hasn't been confirmed, there is the option to cancel in the same dialog that the maintainer was chosen. ::: :::note 一旦所有权转移完成,项目将与 Strapi Cloud 断开连接。作为新所有者,请确保前往项目设置的 *常规*选项卡以重新连接项目。 ::: #### 删除 Strapi Cloud 项目 {#deleting-a-strapi-cloud-project} 🌐 Deleting a Strapi Cloud project 你可以删除任何 Strapi Cloud 项目,但这是永久且不可逆的。相关的域名、部署和数据将被删除,项目的订阅将自动取消。 🌐 You can delete any Strapi Cloud project, but it will be permanent and irreversible. Associated domains, deployments and data will be deleted and the subscription for the project will automatically be canceled. 1. 在 *常规*选项卡的*危险区域*部分,点击**删除项目**按钮。 2. 在对话框中,选择删除项目的原因。 3. 通过点击 **删除项目** 按钮来确认删除你的项目。 ### 环境 {#environments} 🌐 Environments “环境”选项卡允许查看 Strapi Cloud 项目中配置的所有环境,以及创建新的环境。生产环境是默认环境,无法删除。可以根据项目的订阅计划创建其他环境,以便在 Strapi Cloud 项目的独立实例上更安全地工作(例如,一个暂存环境,用于在上线到生产环境前进行测试)。 :::note 你购买的附加环境的计费周期将与你的计划计费周期相匹配。 🌐 The billing cycle of additional environments you purchase will match the billing cycle of your plan. ::: 要创建一个新环境: 🌐 To create a new environment: 1. 点击 **添加新环境** 按钮。 2. 在设置步骤中,填写可用的设置: | 设置名称 | 说明 || ---------------- | ------------------------------------------------------------------------ || 环境名称 | (必填)为你的项目新环境写一个名称。 || Git 分支 | (必填)为你的新环境选择正确的分支。 || 基础目录 | 写入你的新环境的基础目录名称。 || 推送时部署 | 勾选此框以在向所选分支推送更改时自动触发部署。若未启用,则需要手动部署最新更改。 || 导入变量 | 勾选此框从现有环境导入变量名称。值不会被导入,所有变量将保持为空。 | 3. 点击 **确认** 以继续到结账步骤。 4. 查看环境价格、适用税费和按比例调整。 5. 点击 **添加环境** 按钮以创建项目的新环境。然后,你将被重定向到你的 *项目仪表板*,在那里你可以跟踪新环境的创建和首次部署。 :::note 如果在环境创建过程中发生错误,进度指示器将停止并显示错误消息。你将在失败步骤旁看到一个**重试**按钮,允许你重新启动创建过程。 🌐 If an error occurs during the environment creation, the progress indicator will stop and display an error message. You will see a **Retry** button next to the failed step, allowing you to restart the creation process. ::: ### 账单与使用情况 {#billing--usage} 🌐 Billing & Usage “ *账单与使用情况*”标签显示你下次预计付款、当前订阅计划的所有信息以及项目使用情况的详细摘要。它还允许你为项目添加新环境(请 [参考环境部分的文档](#environments))。 通过此标签,你还可以: 🌐 Through this tab, you also have the possibility to: - 点击 **更改** 按钮将被重定向到 *计划* 标签,在那里你可以更改你的订阅计划或计费周期([参见相关文档](#plans)), - 点击 **编辑** 按钮以设置新的付款方式(参见 [相关文档](/cloud/account/account-billing))。 :::note 你可以通过直接从此页面选择付款方式,将专用卡附加到你的项目。这样,你可以使用不同的卡管理你的订阅。 🌐 You can attach a dedicated card to your project by choosing the payment method directly from this page. In that way, you can manage your subscriptions with different cards. ::: :::tip 在 *计费与使用*选项卡的使用情况部分,你可以看到项目当前的每月使用量与项目订阅允许的最大使用量的对比。使用右上角的箭头可以查看项目在任意选定月份的使用情况。 还请注意,如果你的使用情况显示另一种订阅计划更适合你的项目,系统将在 *计费与使用*标签中显示一条消息,建议你可以切换到哪个计划。 ::: ### 计划 {#plans} 🌐 Plans “Plans” 标签显示可用的 Strapi Cloud 计划概览,并允许你更改当前计划或账单周期。 :::info 如果你当前的计划被标记为*旧版*,你将能够切换到新的计划(请参阅[降级部分](#downgrading-to-another-plan))。一旦你切换,你将无法再访问之前的计划。 🌐 If your current plan is labeled as *legacy*, you will be able to sidegrade to a new plan (see [downgrade section](#downgrading-to-another-plan)). Once you sidegrade, you will no longer have access to your previous plan. ::: #### 升级到其他方案 {#upgrading-to-another-plan} 🌐 Upgrading to another plan 计划升级是即时的,并且可以通过每个项目的项目设置进行管理。 🌐 Plan upgrades are immediate and can be managed, for each project, via the project settings. 要将你当前的计划升级到更高级别,请: 🌐 To upgrade your current plan to a higher one: 1. 在项目设置的 *计划*选项卡中,选择按月或按年计费的频率,然后点击你想升级的计划的**升级**按钮。 2. 在打开的窗口中,查看升级的付款详情和条款。 a.(可选)点击 **编辑** 按钮以选择其他付款方式。 b.(可选)点击 **我有折扣码**,在字段中输入你的折扣码,然后点击 **应用** 按钮。 3. 点击 **升级到 [plan name]** 按钮以确认升级。项目将自动重新部署。 #### 降级到另一个计划 {#downgrading-to-another-plan} 🌐 Downgrading to another plan 每个项目的计划降级可以通过项目设置进行管理。然而,降级不会立即生效:当前计划将继续有效,直到当前计费周期结束。 🌐 Plan downgrades can be managed, for each project, via the project settings. Downgrades are, however, not immediately effective: the current plan will remain active until the end of the current billing period. :::caution 在降级之前,请确保检查你的 Strapi Cloud 项目的使用情况:如果你当前的使用量超出了较低套餐的限制,你将面临超额收费的风险。你还可能会失去某些功能的访问权限:例如,降级到 Essential 计划将导致你项目的所有备份丢失。有关更多信息,请参阅 [计费与使用信息](/cloud/getting-started/usage-billing)。 🌐 Make sure to check the usage of your Strapi Cloud project before downgrading: if your current usage exceeds the limits of the lower plan, you are taking the risk of getting charged for overages. You may also lose access to some features: for example, downgrading to the Essential plan would result in the loss of all your project's backups. Please refer to [Information on billing & usage](/cloud/getting-started/usage-billing) for more information. 请注意,如果你有额外的付费环境,则无法降级。你需要先删除计划基础价格中未包含的所有额外环境(请参见 [重置与删除环境](#resetting--deleting-environment)),然后才能安排降级。当从Scale降级到Pro时,额外包含的环境将在降级生效时自动删除。 🌐 Note also that you cannot downgrade if you have additional paid environments. You will first need to delete all additional environments that were not included in the base price of you plan (see [Resetting & Deleting environment](#resetting--deleting-environment)) before you can schedule a downgrade. When downgrading from Scale to Pro, the additional included environment will automatically be deleted when the downgrade takes effect. 如果项目连接了 GitHub 组织仓库,则无法降级到免费计划。要降级,请先在 [已连接的 Git 仓库](#modifying-git-repository--branch) 设置中切换到个人仓库。 🌐 You cannot downgrade to the Free plan if a GitHub organization repository is connected to the project. To downgrade, first switch to a personal repository in the [Connected Git repository](#modifying-git-repository--branch) settings. ::: 要将你当前的计划降级到较低的计划: 🌐 To downgrade your current plan to a lower one: 1. 在项目设置的 *计划*选项卡中,选择按月或按年计费频率,然后点击你想降级到的计划的**降级**按钮。 2. 在打开的窗口中,查看降级条款。 3. 点击 **降级** 按钮以确认降级。项目将自动重新部署。 :::tip 降级将在当前计费周期结束时生效。在更改待处理期间,你可以取消已安排的降级并继续使用当前计划。 🌐 Downgrades are effective at the end of the current billing period. Whilst the change is pending, you can cancel the scheduled downgrade and stay on your current plan. ::: #### 更改账单周期 {#changing-billing-cycle} 🌐 Changing billing cycle 你可以随时在每月和每年计费之间切换项目的计费周期。虽然项目计划和附加组件可以根据你的计费周期按月或按年计费,但超额部分始终按月计费。 🌐 You can switch your project's billing cycle between monthly and yearly billing at any time. While project plans and addons can either be billed monthly or yearly depending on your billing cycle, overages are always billed monthly. 要更改你的计费周期: 🌐 To change your billing cycle: 1. 在项目设置的 *计划*选项卡中,使用计划部分顶部的切换按钮在按月和按年计费之间切换。 2. 点击你当前计划的 **切换到[每月/每年]计费** 按钮。 3. 在打开的窗口中,查看计费周期更改的条款。 4. 点击**确认切换**以确认更改。 :::note 当从年度计费切换到每月计费时,你的计划将在下一个续订日期之前保持年度周期。在更改待处理期间,你可以取消计划中的更改并继续使用当前的计费周期。然而,当从每月计费切换到年度计费时,更改会立即生效。 🌐 When switching from yearly to monthly billing, your plan will remain on its yearly cycle until your next renewal date. Whilst the change is pending, you can cancel the scheduled change and stay on your current billing cycle. When switching from monthly to yearly, however, the change is immediate. ::: ### 发票 {#invoices} 🌐 Invoices “ *发票*”标签显示你的 Strapi Cloud 项目的全部发票列表及其状态。免费计划不提供发票。 :::strapi Invoices are also available in your profile settings. 在 *个人资料 > 发票* 选项卡中,你将找到所有项目的完整发票列表。欢迎查看[专用文档](/cloud/account/account-billing#account-invoices)。 🌐 In the *Profile > Invoices* tab, you will find the complete list of invoices for all your projects. Feel free to check the [dedicated documentation](/cloud/account/account-billing#account-invoices). ::: ## 环境级设置 {#environment-level-settings} 🌐 Environment-level settings 在项目的环境设置中,你首先需要使用下拉菜单选择要配置其设置的环境。根据所选的环境,通常有3到4个可用的选项卡: 🌐 In the project's environments' settings, you first need to select the environment whose settings you would like to configure, using the dropdown. Depending on the chosen environment, there are 3 to 4 tabs available: - [*配置*](#configuration), - [*备份*](#backups),仅适用于生产环境, - [*字段*](#domains), - 和 [*变量*](#variables)。 ### 配置 {#configuration} 🌐 Configuration 环境级设置的 *配置*选项卡使你能够检查和更新项目的以下选项: - *基本信息*,请参见: - 你的 Strapi Cloud 项目的环境名称。环境名称在创建时设置,之后无法修改。 - 环境的 Node 版本:要更改项目的 Node 版本(参见 [修改 Node 版本](#modifying-node-version))。 - 应用用于环境的内部名称,这对于调试和支持目的可能非常有用。 - *已连接的分支*: 用于更改环境所使用的 GitHub 仓库分支(请参阅 [编辑 Git 分支](#editing-git-branch))。还可以启用/禁用“推送时部署”选项。 - *环境数据*:从同一项目内的另一个环境传输数据(参见[在环境之间传输数据](#transferring-data-between-environments))。 - *危险区域*:重置或永久删除你的 Strapi Cloud 项目的环境(参见 [重置和删除环境](#resetting--deleting-environment))。 #### 修改 Node 版本 {#modifying-node-version} 🌐 Modifying Node version 环境的 Node 版本基于创建项目时选择的版本(参见[创建项目](/cloud/getting-started/deployment)),通过高级设置。之后可以为任何环境切换到其他 Node 版本。 🌐 The environment's Node version is based on the one chosen at the creation of the project (see [Creating a project](/cloud/getting-started/deployment)), through the advanced settings. It is possible to switch to another Node version afterwards, for any environment. 1. 在 *配置*选项卡的*基本信息*部分,点击*节点版本*的编辑 按钮。 2. 在对话框中使用 *Node 版本* 下拉菜单,点击你选择的版本。 3. 点击 **保存**,或者如果你希望更改立即生效,就点击 **保存并部署**。 :::tip 在部署之前,确保你在 Strapi 项目中配置的 Node 版本与项目仪表板中显示的 Node 版本匹配。 🌐 Ensure the Node version configured in your Strapi project matches the Node version shown in your project’s dashboard before deploying. ::: #### 编辑 Git 分支 {#editing-git-branch} 🌐 Editing Git branch 1. 在 *编辑分支* 对话框中,编辑可用的设置。请注意,可以通过项目设置同时编辑所有环境的分支,详见 [常规](#general)。 | 设置名称 | 说明 || --------------- | ------------------------------------------------------------------------ || 选择的分支 | (必填)从下拉列表中选择一个分支。 || 基础目录 | 在文本框中填写基础目录的路径。 || 在每次向此分支推送提交时部署项目 | 选中此框可在向所选分支推送新提交时自动触发新部署。取消选中以禁用该选项。 | 2. 点击 **保存并部署** 按钮以使更改生效。 #### 在环境之间传输数据 {#transferring-data-between-environments} 🌐 Transferring data between environments 数据传输功能允许你将整个 CMS 内容(数据库和资源)从一个环境传输到同一 Strapi Cloud 项目中的另一个环境。这对于在次要环境中使用最新的生产数据测试更改,或在将内容投入生产之前在次要环境中准备和排练内容非常有用。 🌐 The data transfer feature allows you to transfer the entire CMS content (database and assets) from one environment to another within the same Strapi Cloud project. This is useful for testing changes in a secondary environment with up-to-date production data, or for preparing and staging content in a secondary environment before taking it to production. 在环境之间传输数据目前存在以下限制: 🌐 Transferring data between environments currently comes with the following limitations: - 你只能转移到辅助环境(不能转移到生产环境)。 - 只有项目所有者才能发起和管理正在进行的转移。 - 暂停的项目无法发起转账。 :::caution Data transfers are destructive 将数据传输到某个环境将永久覆盖目标环境中的所有现有数据和资源。源环境的数据不受影响,并且在传输期间可以访问其 CMS。环境设置(例如变量和域)不会受到传输的影响。 🌐 Transferring data to an environment will permanently overwrite all existing data and assets in the target environment. The source environment's data remains unaffected, and its CMS can be accessed during the transfer. Environment settings (such as variables and domains) are not affected by the transfer. ::: 将数据传输到次要环境: 🌐 To transfer data to a secondary environment: 1. 创建并部署源和目标[环境](#environments)。 2. 在 *配置*选项卡的*环境数据*部分,点击**导入数据**按钮。 3. 在打开的模态窗口中,从下拉列表中选择源环境。只有完全创建并部署的环境可用作源。 4. 点击 **导入数据** 以继续,然后按照步骤确认传输。 5. 一旦启动,你将被重定向到环境的仪表板,在那里你可以监控传输的进度。传输完成后,仪表板将刷新,显示正在进行的和历史的部署。 :::note 在传输进行时,目标环境的 CMS 将无法访问。你可以取消正在进行的传输,但这将使目标环境为空。如果在传输过程中发生错误,你将有选项重新尝试或取消。 🌐 The CMS of the target environment will be inaccessible whilst the transfer is ongoing. You can cancel an ongoing transfer, but this will leave the target environment empty. If an error occurs during the transfer, you will have the option to retry or cancel. ::: #### 重置和删除环境 {#resetting--deleting-environment} 🌐 Resetting & Deleting environment 你可以重置或删除 Strapi Cloud 项目的任何附加环境,但这是永久且不可逆的。然而,默认的生产环境既不能重置也不能删除。 🌐 You can reset or delete any additional environment of your Strapi Cloud project, but it will be permanent and irreversible. The default, production environment, can however neither be reset nor deleted. ##### 重置环境 {#resetting-an-environment} 🌐 Resetting an environment 重置环境会删除所有环境数据,并将变量重置为默认值。操作步骤如下: 🌐 Resetting an environment deletes all environments data and resets the variables to their default. To do so: 1. 在 *配置*选项卡的*危险区域*部分,点击**重置环境**按钮。 2. 在打开的对话框中,点击 **继续** 按钮以确认环境重置。 3. 填写可用字段以重置环境: | 设置名称 | 说明 || --------------- | ------------------------------------------------------------------------ || 环境名称 | (必填)为项目的新环境写一个名称。 || Git 分支 | (必填)从下拉列表中选择一个分支。 || 基目录 | 在文本框中写入基目录的路径。 || 导入变量 | 勾选此框以从现有环境导入变量名。值不会被导入,所有变量将保持为空。 || 自动部署 | 在每次提交到该分支时部署项目。勾选此框以在新提交推送到所选分支时自动触发新的部署。取消勾选以禁用此选项。 | 4. 点击 **重置** 按钮。 ##### 删除环境 {#deleting-an-environment} 🌐 Deleting an environment 1. 在 *配置*选项卡的*危险区域*部分,点击**删除环境**按钮。 2. 在文本框中输入你的*环境名称*。 3. 点击 **删除环境** 按钮以确认删除。 ### 备份 {#backups} 🌐 Backups “ *备份*”标签会通知你 Strapi Cloud 项目的最新备份状态和日期。所有现有 Strapi Cloud 项目关联的数据库确实会自动备份(专业版计划为每周一次,Scale 计划为每日一次)。备份会保留 28 天。此外,你还可以创建单次手动备份。 :::note Notes - 备份功能在免费或基础计划的 Strapi Cloud 项目中不可用。你需要升级到专业版或扩展版计划,以启用自动备份并访问手动备份选项。 - 备份仅包括你默认生产环境的数据库。上传到你的项目的资源和任何辅助环境的数据库不包括在内。 - 项目首次成功部署后不久,手动备份选项就会可用。 ::: :::tip 对于在2023年10月备份功能发布之前创建的项目,首次备份将在下次项目部署时自动触发。 🌐 For projects created before the release of the Backup feature in October 2023, the first backup will automatically be triggered with the next deployment of the project. ::: #### 创建手动备份 {#creating-a-manual-backup} 🌐 Creating a manual backup 要创建手动备份,在 *备份*部分,点击**创建备份**按钮。 手动备份应立即开始,在备份完成之前,恢复或创建其他备份将被禁用。 🌐 The manual backup should start immediately, and restoration or creation of other backups will be disabled until the backup is complete. :::caution 在创建新的手动备份时,任何现有的手动备份都将被删除。你一次只能拥有一个手动备份。 🌐 When creating a new manual backup, any existing manual backup will be deleted. You can only have one manual backup at a time. ::: #### 恢复备份 {#restoring-a-backup} 🌐 Restoring a backup 如果你需要恢复项目的备份: 🌐 If you need to restore a backup of your project: 1. 在 *备份*部分,点击**恢复备份**按钮。 2. 在对话框中,从*选择备份*下拉菜单中选择你项目的可用备份(自动备份或手动备份)之一。 3. 点击对话框中的 **恢复** 按钮。恢复完成后,你的项目将回到所选备份时的状态。你将能够在 *备份* 标签中看到恢复的时间戳和所恢复的备份。 4. 将显示上次完成恢复的时间戳,以帮助你追踪项目上次恢复的时间。 #### 正在下载备份 {#downloading-a-backup} 🌐 Downloading a backup 如果你需要下载项目的备份: 🌐 If you need to download a backup of your project: 1. 在 *备份*部分,点击**下载备份**按钮。 2. 在对话框中,从*选择备份*下拉菜单中选择你项目的可用备份(自动备份或手动备份)之一。 3. 点击对话框中的 **下载** 按钮,以 `.sql` 格式下载所选备份的归档文件。 :::note 备份文件将仅包含你默认生产环境的数据库。它不会包含资源或任何其他环境的数据库。 🌐 The backup file will include only the database of your default Production environment. It will not include assets or any other environment databases. ::: ### 域名 {#domains} 🌐 Domains “Domains”选项卡使你能够管理域并连接新的域名。 你 Strapi Cloud 项目的所有现有域都列在 *域*标签中。对于每个域,你可以: - 查看其当前状态: - 活跃:该域名当前已确认并处于活跃状态 - 待处理:域名转移正在进行中,正在等待 DNS 变更生效 - 失败:由于发生错误,域更改请求未完成 - 点击 编辑按钮以访问域名设置 - 点击 删除按钮以删除域 #### 连接自定义域名 {#connecting-a-custom-domain} 🌐 Connecting a custom domain 默认域名由两个随机生成的单词加上一个哈希组成。它们可以被你选择的任何自定义域名替换。 🌐 Default domain names are made of 2 randomly generated words followed by a hash. They can be replaced by any custom domain of your choice. :::note 自定义域名在免费计划中不可用。降级到免费计划将导致应用域名恢复为默认域名。 🌐 Custom domains are not available on the Free plan. Downgrading to the Free plan will result in the application domain's being restored to the default one. ::: 1. 点击 **连接新域名** 按钮。 2. 在打开的窗口中,填写以下字段: | 设置名称 | 说明 || --- | --- || 域名 | 输入新的域名(例如 *custom-domain-name.com*) || 主机名 | 输入主机名(即终端用户在浏览器中输入的地址,或通过 API 调用的地址)。 || 目标 | 输入目标(即用户输入主机名时重定向到的实际地址)。 || 设置为默认域名 | 勾选此框以将新域名设置为默认域名。 | 3. 点击 **保存并部署** 以使更改生效。 :::tip 要完成自定义域名的设置,请在你的域名注册商或托管平台的设置中,将目标值(例如 `proud-unicorn-123456af.strapiapp.com`)作为 CNAME 别名添加到你域名的 DNS 记录中。 🌐 To finish setting up your custom domain, in the settings of your domain registrar or hosting platform, please add the Target value (e.g., `proud-unicorn-123456af.strapiapp.com`) as a CNAME alias to the DNS records of your domain. ::: :::info Custom domains and assets 使用自定义域名时,这些域名不适用于已上传资源的 URL。已上传的资源保持 Strapi Cloud 基于项目的 URL。 🌐 When using custom domains, these domains do not apply to the URLs of uploaded assets. Uploaded assets keep the Strapi Cloud project-based URL. 这意味着,如果你的自定义域托管在 `https://my-custom-domain.com`,并且你的 Strapi Cloud 项目名称是 `my-strapi-cloud-instance`,API 调用仍将返回类似 `https://my-strapi-cloud-instance.media.strapiapp.com/example.png` 的 URL。 🌐 This means that, if your custom domain is hosted at `https://my-custom-domain.com` and your Strapi Cloud project name is `my-strapi-cloud-instance`, API calls will still return URLs such as `https://my-strapi-cloud-instance.media.strapiapp.com/example.png`. 通过 REST 或 GraphQL 进行的媒体库查询总是返回 Strapi Cloud 上的项目媒体域。如果你从自托管项目迁移,媒体 URL 将不再与你自己的域或 CDN 匹配。请计划使用 API 返回的绝对 URL,或调整前端以允许 Strapi Cloud 媒体域(更多详情请参见 [Cloud Fundamentals](/cloud/cloud-fundamentals))。 🌐 Media library queries over REST or GraphQL always return the project media domain on Strapi Cloud. If you move from a self-hosted project, media URLs will no longer match your own domain or CDN. Plan to use the absolute URLs returned by the API, or adjust your frontend to allow the Strapi Cloud media domain (see [Cloud Fundamentals](/cloud/cloud-fundamentals) for more details). ::: ### 变量 {#variables} 🌐 Variables 环境变量(更多信息请参见 [CMS 文档](/cms/configurations/environment))用于配置你的 Strapi 应用的环境,例如数据库连接。 🌐 Environment variables (more information in the [CMS Documentation](/cms/configurations/environment)) are used to configure the environment of your Strapi application, such as the database connection. 在 *变量*标签中列出了你 Strapi Cloud 项目的默认和自定义环境变量。每个变量由一个*名称*和一个*值*组成。 #### 管理环境变量 {#managing-environment-variables} 🌐 Managing environment variables 将鼠标悬停在环境变量上,无论是默认的还是自定义的,都会显示以下可用选项: 🌐 Hovering on an environment variable, either default or custom, displays the following available options: - **显示值**以使用变量的实际值替换`*`字符。 - **复制到剪贴板**以复制变量的值。 - **操作**以访问 编辑和 删除按钮。 - 编辑默认变量时,*名称*无法修改,*值*只能通过 生成值按钮自动生成。别忘了 **保存**,如果你希望更改立即生效,则选择 **保存并部署**。 - 在编辑自定义变量时,*名称*和*值*都可以通过输入新内容或使用 生成值按钮来修改。别忘了**保存**,如果希望更改立即生效,请选择**保存并部署**。 - 删除变量时,系统会要求你通过选择 **保存** 或 **保存并部署** 来确认,如果你希望更改立即生效请选择 **保存并部署**。 :::tip 使用搜索栏可以更快地在列表中找到环境变量! 🌐 Use the search bar to find more quickly an environment variable in the list! ::: #### 创建自定义环境变量 {#creating-custom-environment-variables} 🌐 Creating custom environment variables 可以为 Strapi Cloud 项目创建自定义环境变量。创建或编辑环境变量后,请确保重新部署你的项目。 🌐 Custom environment variables can be created for the Strapi Cloud project. Make sure to redeploy your project after creating or editing an environment variable. 1. 在*自定义环境变量*部分,点击**添加变量**按钮。 2. 在同名字段中填写新环境变量的*名称*和*值*。或者,你可以点击 图标自动生成名称和值。 3. (可选)点击 **添加另一个** 来直接创建一个或多个其他自定义环境变量。 4. 点击 **保存** 按钮以确认创建自定义环境变量。要立即应用更改,请点击 **保存并部署**。 # 管理面板定制 Source: https://docs.strapi.io/cms/admin-panel-customization # 管理面板定制 {#admin-panel-customization} 🌐 Admin panel customization Strapi 的 **前端部分** 称为管理面板。管理面板提供图形用户界面,帮助你构建和管理通过内容 API 可访问的内容。要了解管理面板的概览,请参考 [入门 > 管理面板](/cms/features/admin-panel) 页面。 从开发者的角度来看,Strapi 的管理面板是一个基于 React 的单页应用,它封装了 Strapi 应用的所有功能和已安装的插件。 🌐 From a developer point of view, Strapi's admin panel is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. 管理员面板的自定义通过调整 `src/admin/app` 文件或 `src/admin` 文件夹中包含的其他文件的代码来完成(参见 [项目结构](/cms/project-structure))。通过这样做,你可以: 🌐 Admin panel customization is done by tweaking the code of the `src/admin/app` file or other files included in the `src/admin` folder (see [project structure](/cms/project-structure)). By doing so, you can: - 自定义管理面板的某些部分,以更好地体现你的品牌标识(徽标、网站图标)或语言。 - 替换管理面板的其他部分,例如富文本编辑器和打包器。 - 扩展主题或管理​​面板以添加新功能或自定义现有用户界面。 :::strapi Plugins and Admin Panel API 除了本节中详细说明的支持自定义功能外,你还可以更进一步,创建可以使用 [管理员面板 API](/cms/plugins-development/admin-panel-api) 的插件。 🌐 In addition to supported customizations detailed in this section, you can go further and create plugins that tap into the [Admin Panel API](/cms/plugins-development/admin-panel-api). ::: ## 一般考虑 {#general-considerations} 🌐 General considerations :::prerequisites 在更新代码以自定义管理面板之前: 🌐 Before updating code to customize the admin panel: - 将默认的 `app.example.tsx|js` 文件重命名为 `app.ts|js`。 - 在 `/src/admin/` 中创建一个新的 `extensions` 文件夹。 - 如果你想在开发时实时看到你的更改生效,请确保管理员面板服务器正在运行(通常如果你没有更改管理员面板的默认[主机、端口和路径](/cms/configurations/admin-panel#admin-panel-server),可以使用 `yarn develop` 或 `npm run develop` 命令来启动)。 ::: 大多数基本的管理面板自定义将在 `/src/admin/app` 文件中完成,该文件包含一个 `config` 对象。 🌐 Most basic admin panel customizations will be done in the `/src/admin/app` file, which includes a `config` object. 任何 `config` 对象使用的文件(例如,自定义徽标)都应放置在 `/src/admin/extensions/` 文件夹中,并在 `/src/admin/app.js` 中导入。 🌐 Any file used by the `config` object (e.g., a custom logo) should be placed in a `/src/admin/extensions/` folder and imported inside `/src/admin/app.js`. 这将替换位于 `./build` 的文件夹内容。访问 ## 基本示例 {#basic-example} 🌐 Basic example 以下是管理面板基本自定义的示例: 🌐 The following is an example of a basic customization of the admin panel: :::strapi Detailed examples in the codebase * 你可以查看完整的翻译键,例如要更改欢迎消息,请访问 [GitHub](https://github.com/strapi/strapi/blob/develop/packages/core/admin/admin/src/translations)。 * 明暗颜色也可以在 [GitHub](https://github.com/strapi/design-system/tree/main/packages/design-system/src/themes) 上找到。 ::: # 管理面板打包器 Source: https://docs.strapi.io/cms/admin-panel-customization/bundlers # 管理面板打包器 {#admin-panel-bundlers} 🌐 Admin panel bundlers Strapi 的 [管理面板](/cms/admin-panel-customization) 是一个基于 React 的单页应用,封装了 Strapi 应用的所有功能和已安装的插件。你的 Strapi 5 应用可以使用两种不同的打包工具,[Vite](#vite)(默认工具)和 [webpack](#webpack)。这两种打包工具都可以根据你的需求进行配置。 🌐 Strapi's [admin panel](/cms/admin-panel-customization) is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. 2 different bundlers can be used with your Strapi 5 application, [Vite](#vite) (the default one) and [webpack](#webpack). Both bundlers can be configured to suit your needs. :::info 为了简化,以下文档提到 `strapi develop` 命令,但实际上你可能会根据所选择的软件包管理器运行 `yarn develop` 或 `npm run develop` 来使用它的别名。 🌐 For simplification, the following documentation mentions the `strapi develop` command, but in practice you will probably use its alias by running either `yarn develop` or `npm run develop` depending on your package manager of choice. ::: ## 快 {#vite} 🌐 Vite 在 Strapi 5 中, ## Webpack 在 Strapi 5 中,默认的打包工具是 Vite。要使用 # 管理面板扩展 Source: https://docs.strapi.io/cms/admin-panel-customization/extension # 管理面板扩展 {#admin-panel-extension} 🌐 Admin panel extension Strapi的[管理面板](/cms/admin-panel-customization)是一个基于React的单页应用,封装了Strapi应用的所有功能和已安装的插件。如果Strapi提供的[自定义选项](/cms/admin-panel-customization#available-customizations)不足以满足你的使用需求,你将需要扩展Strapi的管理面板。 🌐 Strapi's [admin panel](/cms/admin-panel-customization) is a React-based single-page application that encapsulates all the features and installed plugins of a Strapi application. If the [customization options](/cms/admin-panel-customization#available-customizations) provided by Strapi are not enough for your use case, you will need to extend Strapi's admin panel. 扩展 Strapi 的管理面板意味着利用其 React 基础根据项目的特定需求调整和增强界面和功能,这可能意味着创建新组件或添加新类型的字段。 🌐 Extending Strapi's admin panel means leveraging its React foundation to adapt and enhance the interface and features according to the specific needs of your project, which might imply creating new components or adding new types of fields. 在 2 个用例中,你可能需要扩展管理面板: 🌐 There are 2 use cases where you might want to extend the admin panel: | 方法 | 范围 | 入口点 | 文档 ||---|---|---|---|| 本地扩展 | 一个 Strapi 项目 | `/src/admin/app.(js\|ts)` 和 `/src/admin/extensions/` | [管理面板自定义](/cms/admin-panel-customization) || 插件扩展 | 安装了你的插件的任何项目 | `[plugin-name]/admin/src/index.(js\|ts)` | [管理面板 API 概览](/cms/plugins-development/admin-panel-api) | - 作为 Strapi 插件开发者,你希望开发一个 Strapi 插件,使其在**每次安装到任何 Strapi 应用时**都能扩展管理面板。👉 这可以通过利用 [插件的管理面板 API](/cms/plugins-development/admin-panel-api) 来实现,该 API 允许你添加导航链接和设置部分,将 React 组件注入到预定义区域,使用 Redux 管理状态,扩展内容管理器的编辑和列表视图,等等。 - 作为一名 Strapi 开发者,你希望为一个只需要扩展 Strapi 应用特定实例的 Strapi 用户开发一个独特的解决方案。👉 这可以通过直接更新 `/src/admin/app` 文件来完成,该文件可以导入位于 `/src/admin/extensions` 中的任何文件。 ## 何时考虑使用插件 {#when-to-consider-a-plugin-instead} 🌐 When to consider a plugin instead 从在 `/src/admin/app` 中进行直接自定义开始,是满足项目特定需求的正确默认方式。当出现以下一种或多种信号时,考虑转向基于插件的方法: 🌐 Starting with a direct customization in `/src/admin/app` is the right default for project-specific needs. Consider moving to a plugin-based approach when one or more of these signals appear: - 你正在将相同的管理员自定义重复应用到多个 Strapi 项目中。 - 你想要对扩展进行版本控制和分发——无论是内部还是通过 。 - 你需要更强大的自动化测试,独立于单个项目代码库。 - 多个团队需要对同一个扩展进行共享所有权和版本管理。 有关插件开发的完整介绍,请参见 [开发 Strapi 插件](/cms/plugins-development/developing-plugins)。 🌐 For a full introduction to plugin development, see [Developing Strapi plugins](/cms/plugins-development/developing-plugins). :::strapi Additional resources * 如果你正在寻找替换默认富文本编辑器的方法,请参阅[相应页面](/cms/admin-panel-customization/wysiwyg-editor)。 * 要了解插件如何与 Strapi 管理面板集成,请从 [管理面板 API 概述](/cms/plugins-development/admin-panel-api) 开始。 ::: # 网站图标 Source: https://docs.strapi.io/cms/admin-panel-customization/favicon # 网站图标 {#favicon} 🌐 Favicon Strapi 的 [管理面板](/cms/admin-panel-customization) 会在多个地方显示其品牌标识,包括 [徽标](/cms/admin-panel-customization/logos) 和网站图标。替换这些图片可以让你将界面和应用与你的身份相匹配。 🌐 Strapi's [admin panel](/cms/admin-panel-customization) displays its branding on various places, including the [logo](/cms/admin-panel-customization/logos) and the favicon. Replacing these images allows you to match the interface and application to your identity. 更换网站图标有两种方法: 🌐 There are 2 approaches to replacing the favicon: * 替换 Strapi 项目根目录下的 `favicon.png` 文件 * 用以下代码编辑 [`strapi::favicon` 中间件配置](/cms/configurations/middlewares#favicon): ```js title="/config/middlewares.js" // … { name: 'strapi::favicon', config: { path: 'my-custom-favicon.png', }, }, // … ``` 完成后,通过在终端运行 `yarn build && yarn develop` 来重建、启动并重新访问你的 Strapi 应用。 🌐 Once done, rebuild, launch and revisit your Strapi app by running `yarn build && yarn develop` in the terminal. :::caution 确保清除缓存的收藏夹图标。它可能缓存于你的网页浏览器中,也可能缓存于像 Cloudflare 的 CDN 这样的域名管理工具中。 🌐 Make sure that the cached favicon is cleared. It can be cached in your web browser and also with your domain management tool like Cloudflare's CDN. ::: # 首页自定义 Source: https://docs.strapi.io/cms/admin-panel-customization/homepage # 首页自定义 Strapi 管理面板的 :::note The API requires Strapi 5.13+ `app.widgets.register` API 仅适用于 Strapi 5.13 及以上版本。尝试在较旧版本的 Strapi 中调用该 API 会导致管理面板崩溃。 希望注册小部件的插件开发者应当选择以下一种方式: 🌐 The `app.widgets.register` API only works with Strapi 5.13 and above. Trying to call the API with older versions of Strapi will crash the admin panel. Plugin developers who want to register widgets should either: - 在他们的插件 `package.json` 中将 `^5.13.0` 设置为其 `@strapi/strapi` 的 peerDependency。这个 peerDependency 支撑了市场的兼容性检查。 - 或者,在调用 API 之前检查它是否存在: ```js if ('widgets' in app) { // proceed with the registration } ``` 如果插件的全部目的是注册小部件,建议使用 peerDependency 方法。如果插件想添加小部件,但其大部分功能在其他地方,第二种方法更合理。 🌐 The peerDependency approach is recommended if the whole purpose of the plugin is to register widgets. The second approach makes more sense if a plugin wants to add a widget but most of its functionality is elsewhere. ::: #### 组件 API 参考 {#widget-api-reference} 🌐 Widget API reference `app.widgets.register()` 方法可以接受单个小部件配置对象或一个配置对象数组。每个小部件配置对象可以接受以下属性: 🌐 The `app.widgets.register()` method can take either a single widget configuration object or an array of configuration objects. Each widget configuration object can accept the following properties: | 属性 | 类型 | 描述 | 是否必填 ||-------------|------------------------|-------------------------------------------------------|----------|| `icon` | `React.ComponentType` | 显示在小部件标题旁的图标组件 | 是 || `title` | `MessageDescriptor` | 支持翻译的小部件标题 | 是 || `component` | `() => Promise :::tip 为了简单起见,下面的示例在 useEffect 钩子内部直接使用数据获取。虽然这在演示中可行,但它可能不反映生产中的最佳实践。 🌐 For simplicity, the example below uses data fetching directly inside a useEffect hook. While this works for demonstration purposes, it may not reflect best practices in production. 对于更稳健的解决方案,请考虑在[React 文档](https://react.nodejs.cn/learn/build-a-react-app-from-scratch#data-fetching)中推荐的替代方法。如果你希望集成数据获取库,我们建议使用[TanStackQuery](https://tanstack.com/query/v3/)。 🌐 For more robust solutions, consider alternative approaches recommended in the [React documentation](https://react.nodejs.cn/learn/build-a-react-app-from-scratch#data-fetching). If you're looking to integrate a data fetching library, we recommend using [TanStackQuery](https://tanstack.com/query/v3/). ::: **数据管理**: ![Rendering and Data management](/img/assets/homepage-customization/rendering-data-management.png) 上方的绿色框表示用户的 React 组件(来自 [API](#widget-api-reference) 中的 `widget.component`)被渲染的区域。你可以在这个框内渲染你想要的任何内容。然而,框外的所有内容都是由 Strapi 渲染的。这确保了管理员面板内整体设计的一致性。API 提供的 `icon`、`title` 和(可选的)`link` 属性用于显示小部件。 🌐 The green box above represents the area where the user’s React component (from `widget.component` in the [API](#widget-api-reference)) is rendered. You can render whatever you like inside of this box. Everything outside that box is, however, rendered by Strapi. This ensures overall design consistency within the admin panel. The `icon`, `title`, and `link` (optional) properties provided in the API are used to display the widget. #### 小部件辅助组件参考 {#widget-helper-components-reference} 🌐 Widget helper components reference Strapi 提供了几个辅助组件,以便在各个小部件之间保持一致的用户体验: 🌐 Strapi provides several helper components to maintain a consistent user experience across widgets: | 组件 | 描述 | 用法 ||------------------|-----------------------------------------------------|--------------------------------------|| `Widget.Loading` | 显示加载旋转器和消息 | 当数据正在加载时 || `Widget.Error` | 显示错误状态 | 当发生错误时 || `Widget.NoData` | 当没有可用数据时显示 | 当小部件没有数据可显示时 || `Widget.NoPermissions` | 当用户缺少所需权限时显示 | 当用户无法访问该小部件时 | 这些组件有助于在不同的部件中保持一致的外观和感觉。 你可以在没有子组件的情况下渲染这些组件以获得默认文案:` ))} ); }; ``` 以下文件定义了一个自定义控制器,用于统计所有内容类型: 🌐 The following file defines a custom controller that counts all content-types: ```js title="src/plugins/content-metrics/server/src/controllers/metrics.js" 'use strict'; module.exports = ({ strapi }) => ({ async getContentCounts(ctx) { try { // Get all content types const contentTypes = Object.keys(strapi.contentTypes) .filter(uid => uid.startsWith('api::')) .reduce((acc, uid) => { const contentType = strapi.contentTypes[uid]; acc[contentType.info.displayName || uid] = 0; return acc; }, {}); // Count entities for each content type for (const [name, _] of Object.entries(contentTypes)) { const uid = Object.keys(strapi.contentTypes) .find(key => strapi.contentTypes[key].info.displayName === name || key === name ); if (uid) { // Using the count() method from the Document Service API const count = await strapi.documents(uid).count(); contentTypes[name] = count; } } ctx.body = contentTypes; } catch (err) { ctx.throw(500, err); } } }); ``` 以下文件确保指标控制器可以通过自定义的 `/count` 路由访问: 🌐 The following file ensures that the metrics controller is reachable at a custom `/count` route: ```js title="src/plugins/content-metrics/server/src/routes/index.js" 'content-api': { type: 'content-api', routes: [ { method: 'GET', path: '/count', handler: 'metrics.getContentCounts', config: { policies: [], }, }, ], }, }; ``` ))} ); }; ``` 以下文件定义了一个自定义控制器,用于统计所有内容类型: 🌐 The following file defines a custom controller that counts all content-types: ```js title="src/plugins/content-metrics/server/src/controllers/metrics.js" 'use strict'; module.exports = ({ strapi }) => ({ async getContentCounts(ctx) { try { // Get all content types const contentTypes = Object.keys(strapi.contentTypes) .filter(uid => uid.startsWith('api::')) .reduce((acc, uid) => { const contentType = strapi.contentTypes[uid]; acc[contentType.info.displayName || uid] = 0; return acc; }, {}); // Count entities for each content type using Document Service for (const [name, _] of Object.entries(contentTypes)) { const uid = Object.keys(strapi.contentTypes) .find(key => strapi.contentTypes[key].info.displayName === name || key === name ); if (uid) { // Using the count() method from Document Service instead of strapi.db.query const count = await strapi.documents(uid).count(); contentTypes[name] = count; } } ctx.body = contentTypes; } catch (err) { ctx.throw(500, err); } } }); ``` 以下文件确保指标控制器可以通过自定义的 `/count` 路由访问: 🌐 The following file ensures that the metrics controller is reachable at a custom `/count` route: ```js title="src/plugins/content-metrics/server/src/routes/index.js" 'content-api': { type: 'content-api', routes: [ { method: 'GET', path: '/count', handler: 'metrics.getContentCounts', config: { policies: [], }, }, ], }, }; ``` # 本地化与翻译 Source: https://docs.strapi.io/cms/admin-panel-customization/locales-translations # 本地化与翻译 {#locales--translations} 🌐 Locales & translations Strapi [管理面板](/cms/admin-panel-customization) 默认提供英文字符串,并支持添加其他语言环境,以便你的编辑团队可以使用他们偏好的语言进行工作。语言环境决定界面中显示的语言,而翻译则提供在某个语言环境中每个键显示的文本。 🌐 The Strapi [admin panel](/cms/admin-panel-customization) ships with English strings and supports adding other locales so your editorial team can work in their preferred language. Locales determine which languages appear in the interface, while translations provide the text displayed for each key in a locale. 本指南面向从应用代码库自定义管理体验的项目维护者。所有示例都修改从 `/src/admin/app` 文件导出的配置,Strapi 在构建管理面板时会加载该配置。你将学习如何声明额外的语言环境,以及当语言环境缺少字符串时如何扩展 Strapi 或插件的翻译。 🌐 This guide targets project maintainers customizing the admin experience from the application codebase. All examples modify the configuration exported from `/src/admin/app` file, which Strapi loads when the admin panel builds. You'll learn how to declare additional locales and how to extend Strapi or plugin translations when a locale is missing strings. ## 定义区域设置 {#defining-locales} 🌐 Defining locales 要在管理面板中更新可用语言环境列表,请在 `src/admin/app` 文件中设置 `config.locales` 数组: 🌐 To update the list of available locales in the admin panel, set the `config.locales` array in `src/admin/app` file: :::note Notes - `en` 语言环境无法从构建中移除,因为它既是回退语言环境(即如果在某个语言环境中未找到翻译,将使用 `en`),也是默认语言环境(即当用户第一次打开管理面板时使用)。 - 可用区域设置的完整列表可在 插件的键/值对在插件的文件 `/admin/src/translations/[language-name].json` 中独立声明。这些键/值对可以通过在 `config.translations` 键中添加前缀(插件的名称,即 `[plugin name].[key]: 'value'`)来类似地扩展,如以下示例所示: 🌐 A plugin's key/value pairs are declared independently in the plugin's files at `/admin/src/translations/[language-name].json`. These key/value pairs can similarly be extended in the `config.translations` key by prefixing the key with the plugin's name (i.e. `[plugin name].[key]: 'value'`) as in the following example: 如果你需要发送额外的翻译 JSON 文件——例如为了组织大型覆盖或支持 Strapi 未打包的本地化——请将它们放在 `/src/admin/extensions/translations` 文件夹中,并确保本地化代码已列在 `config.locales` 中。 🌐 If you need to ship additional translation JSON files—for example to organize large overrides or to support a locale not bundled with Strapi—place them in the `/src/admin/extensions/translations` folder and ensure the locale code is listed in `config.locales`. :::tip Rebuild the admin 当管理员重建时,翻译更改会生效。如果更新未显示,请重新运行开发服务器或重建管理员以刷新打包的翻译。 🌐 Translation changes apply when the admin rebuilds. If updates don’t show, re-run your dev server or rebuild the admin to refresh bundled translations. ::: # 标志 Source: https://docs.strapi.io/cms/admin-panel-customization/logos # 标志 {#logos} 🌐 Logos Strapi 的 [管理面板](/cms/admin-panel-customization) 在登录屏幕和主导航中显示其品牌标识。更换这些图片可以让界面与你的身份保持一致。本页展示了如何通过管理面板配置覆盖这两个徽标文件。如果你更喜欢直接在 UI 中上传,请参见 [自定义徽标](/cms/features/admin-panel#customizing-the-logo)。 🌐 Strapi's [admin panel](/cms/admin-panel-customization) displays its branding on both the login screen and in the main navigation. Replacing these images allows you to match the interface to your identity. The present page shows how to override the two logo files via the admin panel configuration. If you prefer uploading them directly in the UI, see [Customizing the logo](/cms/features/admin-panel#customizing-the-logo). Strapi 管理面板在 2 个不同位置显示徽标,由管理面板配置中的 2 个不同键表示: 🌐 The Strapi admin panel displays a logo in 2 different locations, represented by 2 different keys in the admin panel configuration: | 在用户界面中的位置 | 要更新的配置键 || --- | --- || 在登录页面 | `config.auth.logo` || 在主导航中 | `config.menu.logo` | :::note 通过管理面板上传的徽标将取代通过配置文件设置的任何徽标。 🌐 Logos uploaded via the admin panel supersede any logo set through the configuration files. ::: ### 管理面板中的标志位置 {#logos-location-in-the-admin-panel} 🌐 Logos location in the admin panel `config.auth.logo` 处理的徽标只显示在登录屏幕上: 🌐 The logo handled by `config.auth.logo` logo is only shown on the login screen: ![Location of the auth logo](/img/assets/development/config-auth-logo.png) `config.menu.logo` 处理的徽标位于管理员面板左上角的主导航中: 🌐 The logo handled by `config.menu.logo` logo is located in the main navigation at the top left corner of the admin panel: ![Location of Menu logo](/img/assets/development/config-menu-logo.png) ### 更新标志 {#updating-logos} 🌐 Updating logos 要更新徽标,请将图片文件放入 `/src/admin/extensions` 文件夹,在 `src/admin/app` 中导入这些文件,并按以下示例更新相应的键: 🌐 To update the logos, put image files in the `/src/admin/extensions` folder, import these files in `src/admin/app` and update the corresponding keys as in the following example: :::note 通过配置文件设置的图片文件没有大小限制。 🌐 There is no size limit for image files set through the configuration files. ::: # 主题扩展 Source: https://docs.strapi.io/cms/admin-panel-customization/theme-extension # 主题扩展 {#theme-extension} 🌐 Theme extension Strapi 的 [管理面板](/cms/admin-panel-customization) 可以显示为浅色或夜间模式(参见 [个人资料设置](/cms/getting-started/setting-up-admin-panel#setting-up-your-administrator-profile)),两者都可以通过自定义主题设置进行扩展。 🌐 Strapi's [admin panel](/cms/admin-panel-customization) can be displayed either in light or dark mode (see [profile setup](/cms/getting-started/setting-up-admin-panel#setting-up-your-administrator-profile)), and both can be extended through custom theme settings. 要扩展主题,请使用: 🌐 To extend the theme, use either: - Light 模式的 `config.theme.light` 键 - `config.theme.dark` 键用于夜间模式 :::strapi Strapi Design System 默认的 # 自定义富文本编辑器 Source: https://docs.strapi.io/cms/admin-panel-customization/wysiwyg-editor # 更改默认富文本编辑器 {#change-the-default-rich-text-editor} 🌐 Change the default rich text editor Strapi 的 [管理面板](/cms/admin-panel-customization) 附带了一个内置的富文本编辑器。要更改默认编辑器,你有几种选择: 🌐 Strapi's [admin panel](/cms/admin-panel-customization) comes with a built-in rich text editor. To change the default editor, several options are at your disposal: - 你可以通过访问 安装第三方插件,例如用于CKEditor的插件。 - 你可以创建自己的插件来创建和注册一个完全自定义的所见即所得字段(参见 [自定义字段文档](/cms/features/custom-fields))。 :::tip Next steps 评估编辑器时,建议先从 Marketplace 下载插件进行快速试用,如果需要更深入的集成(例如架构、验证或自定义工具栏行为),则可以考虑使用自定义字段。 🌐 When evaluating editors, start with a plugin from the Marketplace for a quick trial, then consider a custom field if you need deeper integration (schema, validation, or custom toolbar behavior). ::: # Strapi 客户端 Source: https://docs.strapi.io/cms/api/client # Strapi 客户端 {#strapi-client} 🌐 Strapi Client Strapi 客户端库简化了与 Strapi 后端的交互,提供了一种获取、创建、更新和删除内容的方式。本指南将引导你完成 Strapi 客户端的设置、身份验证配置,以及有效使用其主要功能。 🌐 The Strapi Client library simplifies interactions with your Strapi back end, providing a way to fetch, create, update, and delete content. This guide walks you through setting up the Strapi Client, configuring authentication, and using its key features effectively. ## 入门 {#getting-started} 🌐 Getting Started :::prerequisites - Strapi 项目已创建并正在运行。如果你还没有设置,请按照[快速入门指南](/cms/quick-start)创建一个。 - 你知道你的 Strapi 实例的内容 API 的 URL(例如,`http://localhost:1337/api`)。 ::: ### 安装 {#installation} 🌐 Installation 要在你的项目中使用 Strapi 客户端,请使用你首选的包管理器将其作为依赖安装: 🌐 To use the Strapi Client in your project, install it as a dependency using your preferred package manager: ### 基本配置 {#basic-configuration} 🌐 Basic configuration 要开始与 Strapi 后端交互,请初始化 Strapi 客户端并设置基本 API URL: 🌐 To start interacting with your Strapi back end, initialize the Strapi Client and set the base API URL: `baseURL` 必须包含协议(`http` 或 `https`)。无效的 URL 将抛出错误 `StrapiInitializationError`。 🌐 The `baseURL` must include the protocol (`http` or `https`). An invalid URL will throw an error `StrapiInitializationError`. ### 身份验证 {#authentication} 🌐 Authentication Strapi 客户端支持不同的身份验证策略来访问 Strapi 后端中受保护的资源。 🌐 The Strapi Client supports different authentication strategies to access protected resources in your Strapi back end. 如果你的 Strapi 实例使用 [API 令牌](/cms/features/api-tokens),请按如下方式配置 Strapi 客户端: 🌐 If your Strapi instance uses [API tokens](/cms/features/api-tokens), configure the Strapi Client as follows: ```js const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token-here', }); ``` 这允许你的请求自动包含必要的身份验证凭据。如果令牌无效或缺失,客户端在初始化时将抛出错误 `StrapiValidationError`。 🌐 This allows your requests to include the necessary authentication credentials automatically. If the token is invalid or missing, the client will throw an error during initialization `StrapiValidationError`. ## API参考 {#api-reference} 🌐 API Reference Strapi 客户端提供以下关键属性和方法用于与你的 Strapi 后端交互: 🌐 The Strapi Client provides the following key properties and methods for interacting with your Strapi back end: | 参数 | 描述 || ---| --- || `baseURL` | 你的 Strapi 后端的基础 API URL。 || `fetch()` | 一个用于发起通用 API 请求的工具方法,类似于原生 fetch API。 || `collection()` | 管理集合类型资源(例如博客文章、产品)。 || `single()` | 管理单一类型资源(例如主页设置、全局配置)。 || `files()` | 直接向 Strapi 媒体库上传、检索和管理文件的功能。 | ### 通用抓取 {#general-purpose-fetch} 🌐 General purpose fetch Strapi 客户端提供了对底层 JavaScript `fetch` 函数的访问,以便直接进行 API 请求。请求总是相对于客户端初始化时提供的基础 URL: 🌐 The Strapi Client provides access to the underlying JavaScript `fetch` function to make direct API requests. The request is always relative to the base URL provided during client initialization: ```js const result = await client.fetch('articles', { method: 'GET' }); ``` ### 与集合类型一起工作 {#working-with-collection-types} 🌐 Working with collection types Strapi 中的集合类型是具有多个条目的实体(例如,拥有多篇文章的博客)。Strapi 客户端提供了一个 `collection()` 方法来与这些资源进行交互,具有以下可用方法: 🌐 Collection types in Strapi are entities with multiple entries (e.g., a blog with many posts). The Strapi Client provides a `collection()` method to interact with these resources, with the following methods available: | 参数 | 描述 || ---| --- || `find(queryParams?)` | 获取多个文档,可选择进行过滤、排序或分页。 || `findOne(documentID, queryParams?)` | 通过其唯一 ID 检索单个文档。 || `create(data, queryParams?)` | 在集合中创建一个新文档。 || `update(documentID, data, queryParams?)` | 更新现有文档。 || `delete(documentID, queryParams?)` | 更新现有文档。 | **使用示例:** ### 处理单一类型 {#working-with-single-types} 🌐 Working with single types Strapi 中的单一类型表示只存在一次的独特内容条目(例如首页设置或全站配置)。Strapi 客户端提供了 `single()` 方法来与这些资源进行交互,可用的方法如下:| 参数 | 描述 || ----------| -------------------------------------------------------------------------------------------- || `find(queryParams?)` | 获取文档。 || `update(documentID, data, queryParams?)` | 更新文档。 || `delete(queryParams?)` | 删除文档。 | 🌐 Single types in Strapi represent unique content entries that exist only once (e.g., the homepage settings or site-wide configurations). The Strapi Client provides a `single()` method to interact with these resources, with the following methods available:| Parameter | Description || ----------| -------------------------------------------------------------------------------------------- || `find(queryParams?)` | Fetch the document. || `update(documentID, data, queryParams?)` | Update the document. || `delete(queryParams?)` | Remove the document. | **使用示例:** ```js const homepage = client.single('homepage'); // Fetch the default homepage content const defaultHomepage = await homepage.find(); // Fetch the Spanish version of the homepage const spanishHomepage = await homepage.find({ locale: 'es' }); // Update the homepage draft content const updatedHomepage = await homepage.update( { title: 'Updated Homepage Title' }, { status: 'draft' } ); // Delete the homepage content await homepage.delete(); ``` ### 处理文件 {#working-with-files} 🌐 Working with files Strapi 客户端通过 `files` 属性提供对 [媒体库](/cms/features/media-library) 的访问。这使你能够在不直接与 REST API 交互的情况下检索和管理文件元数据。 🌐 The Strapi Client provides access to the [Media Library](/cms/features/media-library) via the `files` property. This allows you to retrieve and manage file metadata without directly interacting with the REST API. 以下方法可用于处理文件。点击表格中的方法名称即可跳转到相应部分,查看更多详细信息和示例: 🌐 The following methods are available for working with files. Click on the method name in the table to jump to the corresponding section with more details and examples: | 方法 | 描述 ||--------|-------------|| [`find(params?)`](#find) | 根据可选查询参数检索文件元数据列表 || [`findOne(fileId)`](#findone) | 根据文件 ID 检索单个文件的元数据 || [`update(fileId, fileInfo)`](#update) | 更新现有文件的元数据 || [`upload(file, options)`](#upload) | 上传文件(Blob 或 Buffer),可选提供用于元数据的 `options` 对象 || [`delete(fileId)`](#delete) | 根据文件 ID 删除文件 | #### `find` `strapi.client.files.find()` 方法根据可选查询参数检索文件元数据列表。 🌐 The `strapi.client.files.find()` method retrieves a list of file metadata based on optional query parameters. 该方法的使用方式如下: 🌐 The method can be used as follows: ```js // Initialize the client const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // Find all file metadata const allFiles = await client.files.find(); console.log(allFiles); // Find file metadata with filtering and sorting const imageFiles = await client.files.find({ filters: { mime: { $contains: 'image' }, // Only get image files name: { $contains: 'avatar' }, // Only get files with 'avatar' in the name }, sort: ['name:asc'], // Sort by name in ascending order }); ``` #### `findOne` {#findone} `strapi.client.files.findOne()` 方法通过其 ID 检索单个文件的元数据。 🌐 The `strapi.client.files.findOne()` method retrieves the metadata for a single file by its id. 该方法的使用方式如下: 🌐 The method can be used as follows: ```js // Initialize the client const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // Find file metadata by ID const file = await client.files.findOne(1); console.log(file.name); console.log(file.url); console.log(file.mime); // The file MIME type ``` #### `update` `strapi.client.files.update()` 方法更新现有文件的元数据,接受两个参数,`fileId`,以及包含选项的对象,例如媒体的名称、替代文本和标题。 🌐 The `strapi.client.files.update()` method updates metadata for an existing file, accepting 2 parameters, the `fileId`, and an object containing options such as the name, alternative text, and caption for the media. 这些方法的使用方式如下: 🌐 The methods can be used as follows: ```js // Initialize the client const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // Update file metadata const updatedFile = await client.files.update(1, { name: 'New file name', alternativeText: 'Descriptive alt text for accessibility', caption: 'A caption for the file', }); ``` #### `upload` ##### 响应结构 {#response-structure} 🌐 Response Structure `strapi.client.files.upload()` 方法返回一个文件对象数组,每个对象都有如下字段: 🌐 The `strapi.client.files.upload()` method returns an array of file objects, each with fields such as: ```json { "id": 1, "name": "image.png", "alternativeText": "Uploaded from Node.js Buffer", "caption": "Example upload", "mime": "image/png", "url": "/uploads/image.png", "size": 12345, "createdAt": "2025-07-23T12:34:56.789Z", "updatedAt": "2025-07-23T12:34:56.789Z" } ``` :::note Additional response fields 上传响应包括上述显示内容之外的其他字段。有关所有可用字段,请参阅 中的完整 FileResponse 接口。 ::: #### `delete` `strapi.client.files.delete()` 方法通过其 ID 删除文件。 🌐 The `strapi.client.files.delete()` method deletes a file by its ID. 该方法的使用方式如下: 🌐 The method can be used as follows: ```js // Initialize the client const client = strapi({ baseURL: 'http://localhost:1337/api', auth: 'your-api-token', }); // Delete a file by ID const deletedFile = await client.files.delete(1); console.log('File deleted successfully'); console.log('Deleted file ID:', deletedFile.id); console.log('Deleted file name:', deletedFile.name); ```
## 处理常见错误 {#handling-common-errors} 🌐 Handling Common Errors 通过 Strapi 客户端发送查询时可能会出现以下错误: 🌐 The following errors might occur when sending queries through the Strapi Client: | 错误 | 描述 ||-------|-------------|| 权限错误 | 如果经过身份验证的用户没有上传或管理文件的权限,将抛出 `FileForbiddenError`。 || HTTP 错误 | 如果服务器无法访问、身份验证失败或存在网络问题,将抛出 `HTTPError`。 || 缺少参数 | 当上传 `Buffer` 时,必须在选项对象中提供 `filename` 和 `mimetype`。如果缺少任何一个,将抛出错误。 | :::strapi Additional information 有关 Strapi 客户端的更多详细信息可以在 中找到。 ::: # 内容 API Source: https://docs.strapi.io/cms/api/content-api # Strapi API 访问你的内容 {#strapi-apis-to-access-your-content} 🌐 Strapi APIs to access your content 一旦你创建并配置了一个 Strapi 项目,使用 [内容类型构建器](/cms/features/content-type-builder) 创建了内容结构,并通过 [内容管理器](/cms/features/content-manager) 开始添加数据,你可能希望访问你的内容。 🌐 Once you've created and configured a Strapi project, created a content structure with the [Content-Type Builder](/cms/features/content-type-builder) and started adding data through the [Content Manager](/cms/features/content-manager), you likely would like to access your content. 从前端应用,你的内容可以通过 Strapi 的 Content API 访问,该 API 公开: 🌐 From a front-end application, your content can be accessed through Strapi's Content API, which is exposed: - 默认通过 [REST API](/cms/api/rest) - 如果你安装了 Strapi 内置的 [GraphQL 插件](/cms/plugins/graphql),也可以通过 [GraphQL API](/cms/api/graphql) 访问。 你也可以使用 [Strapi Client](/cms/api/client) 库与 REST API 进行交互。 🌐 You can also use the [Strapi Client](/cms/api/client) library to interact with the REST API. REST 和 GraphQL API 代表了面向外部应用暴露的内容 API 的顶层。Strapi 还提供了两个较低层次的 API: 🌐 REST and GraphQL APIs represent the top-level layers of the Content API exposed to external applications. Strapi also provides 2 lower-level APIs: - [文档服务 API](/cms/api/document-service),可通过 `strapi.documents` 访问,是在 [后端服务器](/cms/customization) 内或通过 [插件](/cms/plugins-development/developing-plugins) 与你的应用数据库交互的推荐 API。文档服务是处理 **文档** # 文件 Source: https://docs.strapi.io/cms/api/document
# 文件 {#documents} 🌐 Documents 在 Strapi 5 中,**文档**是一个仅限 API 的概念。文档代表了给定内容类型条目所有不同的内容变体。 🌐 A **document** in Strapi 5 is an API-only concept. A document represents all the different variations of content for a given entry of a content-type. 单一类型包含一个唯一文档,而集合类型可以包含多个文档。 🌐 A single type contains a unique document, and a collection type can contain several documents. 当你使用管理员面板时,从未提到文档的概念,并且对终端用户并不必要。用户在[内容管理器](/cms/features/content-manager)中创建和编辑**条目**。例如,作为用户,你要么列出给定语言环境下的条目,要么编辑给定语言环境中特定条目的草稿版本。 🌐 When you use the admin panel, the concept of a document is never mentioned and not necessary for the end user. Users create and edit **entries** in the [Content Manager](/cms/features/content-manager). For instance, as a user, you either list the entries for a given locale, or edit the draft version of a specific entry in a given locale. 但是,在 API 级别,条目字段的值实际上可以具有: 🌐 However, at the API level, the value of the fields of an entry can actually have: - 英语和法语语言环境的内容不同, - 甚至在每个语言环境中为草稿和已发布版本设置不同的内容。 包含所有语言环境的所有草稿和已发布版本内容的存储桶是一个文档。 🌐 The bucket that includes the content of all the draft and published versions for all the locales is a document. 使用 [文档服务 API](/cms/api/document-service) 操作文档将帮助你创建、检索、更新和删除文档或其中包含的特定数据子集。 🌐 Manipulating documents with the [Document Service API](/cms/api/document-service) will help you create, retrieve, update, and delete documents or a specific subset of the data they contain. 下列图表显示了内容的所有可能变体,这取决于内容类型启用了哪些功能,例如[国际化 (i18n)](/cms/features/internationalization)和[草稿与发布](/cms/features/draft-and-publish): 🌐 The following diagrams represent all the possible variations of content depending on which features, such as [Internationalization (i18n)](/cms/features/internationalization) and [Draft & Publish](/cms/features/draft-and-publish), are enabled for a content-type: - 如果内容类型启用了国际化 (i18n) 功能,则一个文档可以拥有多个**文档语言环境**。 - 如果在内容类型上启用了“草稿与发布”功能,文档可以同时拥有**已发布**版本和**草稿**版本。 :::strapi APIs to query documents data 要与文档或它们所代表的数据进行交互: 🌐 To interact with documents or the data they represent: - 从后端服务器(例如,从控制器、服务以及插件的后端部分)使用 [文档服务 API](/cms/api/document-service)。 - 从应用的前端部分,使用 [REST API](/cms/api/rest) 或 [GraphQL API](/cms/api/graphql) 查询你的数据。 有关 API 的更多信息,请参阅 [内容 API 介绍](/cms/api/content-api)。 🌐 For additional information about the APIs, please refer to the [Content API introduction](/cms/api/content-api). ::: :::info Default version in returned results 后端和前端 API 之间的一个重要区别是关于未传递参数时返回的默认版本: 🌐 An important difference between the back-end and front-end APIs is about the default version returned when no parameter is passed: - 文档服务 API 默认返回草稿版本, - 而 REST 和 GraphQL API 默认返回已发布的版本。 :::
# 文档服务 API Source: https://docs.strapi.io/cms/api/document-service # 文档服务 API {#document-service-api} 🌐 Document Service API 文档服务 API 建立在 **查询引擎 API** 之上 并用于对 **文档** 执行 CRUD([创建](#create)、[检索](#findone)、[更新](#update) 和 [删除](#delete))操作 :::strapi Entity Service API is deprecated in Strapi 5 文档服务 API 取代了 Strapi v4 ( `findOne()` 方法在找到时返回匹配的文档,否则返回 `null`。 🌐 The `findOne()` method returns the matching document if found, otherwise returns `null`. ### `findFirst()` 查找与参数匹配的第一个文档。 🌐 Find the first document matching the parameters. 语法:`findFirst(parameters: Params) => Document` 🌐 Syntax: `findFirst(parameters: Params) => Document` #### 参数 {#parameters-1} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#find-first) | 要查找的文档的语言环境。 | 默认语言环境 | 字符串或 `undefined` | | [`status`](/cms/api/document-service/status#find-first) | _如果内容类型启用了 [Draft & Publish](/cms/features/draft-and-publish)_:
发布状态,可以是: | `'draft'` | `'published'` 或 `'draft'` | | [`filters`](/cms/api/document-service/filters) | 使用的[筛选器](/cms/api/document-service/filters) | `null` | 对象 | | [`fields`](/cms/api/document-service/fields#findfirst) | [选择返回的字段](/cms/api/document-service/fields#findfirst) | 所有字段
(除默认未填充的字段外) | 对象 | | [`populate`](/cms/api/document-service/populate) | [Populate](/cms/api/document-service/populate) 用额外的字段填充结果。 | `null` | 对象 | #### 例子 {#examples} 🌐 Examples
##### 通用示例 {#generic-example} 🌐 Generic example 默认情况下,`findFirst()` 会返回传入唯一标识符(集合类型 ID 或单类型 ID)的第一个文档的草稿版本,使用默认语言环境: 🌐 By default, `findFirst()` returns the draft version, in the default locale, of the first document for the passed unique identifier (collection type id or single type id): ##### 查找符合参数的第一个文档 {#find-the-first-document-matching-parameters} 🌐 Find the first document matching parameters 向 `findFirst()` 传递一些参数以返回与之匹配的第一个文档。 🌐 Pass some parameters to `findFirst()` to return the first document matching them. 如果未传入 `locale` 或 `status` 参数,结果将返回默认语言环境的草稿版本: 🌐 If no `locale` or `status` parameters are passed, results return the draft version for the default locale: ### `findMany()` 查找与参数匹配的文档。 🌐 Find documents matching the parameters. 语法:`findMany(parameters: Params) => Document[]` 🌐 Syntax: `findMany(parameters: Params) => Document[]` #### 参数 {#parameters-2} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 | |-----------|-------------|---------|------| | [`locale`](/cms/api/document-service/locale#find-many) | 要查找的文档的区域设置。 | 默认区域设置 | 字符串或 `undefined` | | [`status`](/cms/api/document-service/status#find-many) | _如果内容类型启用了 [Draft & Publish](/cms/features/draft-and-publish)_:
发布状态,可以是: | `'draft'` | `'published'` 或 `'draft'` | | [`filters`](/cms/api/document-service/filters) | 使用的[筛选器](/cms/api/document-service/filters) | `null` | 对象 | | [`fields`](/cms/api/document-service/fields#findmany) | [选择返回的字段](/cms/api/document-service/fields#findmany) | 所有字段
(除默认未填充的字段外) | 对象 | | [`populate`](/cms/api/document-service/populate) | [Populate](/cms/api/document-service/populate) 用额外的字段填充结果。 | `null` | 对象 | | [`pagination`](/cms/api/document-service/sort-pagination#pagination) | [分页](/cms/api/document-service/sort-pagination#pagination) 结果 | | [`sort`](/cms/api/document-service/sort-pagination#sort) | [排序](/cms/api/document-service/sort-pagination#sort) 结果 | | | #### 例子 {#examples-1} 🌐 Examples
##### 通用示例 {#generic-example-1} 🌐 Generic example 当没有传入参数时,`findMany()` 会返回每个文档在默认语言环境下的草稿版本: 🌐 When no parameter is passed, `findMany()` returns the draft version in the default locale for each document: ##### 查找符合参数的文档 {#find-documents-matching-parameters} 🌐 Find documents matching parameters 可用的过滤器详细信息请参见文档服务 API 参考中的 [filters](/cms/api/document-service/filters) 页面。 🌐 Available filters are detailed in the [filters](/cms/api/document-service/filters) page of the Document Service API reference. 如果未传入 `locale` 或 `status` 参数,结果将返回默认语言环境的草稿版本: 🌐 If no `locale` or `status` parameters are passed, results return the draft version for the default locale: ### `create()` 创建草稿文档并返回它。 🌐 Creates a drafted document and returns it. 传递字段以在 `data` 对象中创建内容。 🌐 Pass fields for the content to create in a `data` object. 语法:`create(parameters: Params) => Document` 🌐 Syntax: `create(parameters: Params) => Document` #### 参数 {#parameters-3} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| [`locale`](/cms/api/document-service/locale#create) | 要创建的文档的语言环境。 | 默认语言环境 | 字符串或 `undefined` || [`fields`](/cms/api/document-service/fields#create) | 要返回的 [选择字段](/cms/api/document-service/fields#create) | 所有字段
(默认未填充的字段除外) | 对象 || [`status`](/cms/api/document-service/status#create) | _如果内容类型启用了 [草稿与发布](/cms/features/draft-and-publish)_:
可以设置为 `'published'`,以在创建文档时自动发布草稿版本 | - | `'published'` || [`populate`](/cms/api/document-service/populate) | 使用附加字段 [填充](/cms/api/document-service/populate) 结果。 | `null` | 对象 | #### 例子 {#example-1} 🌐 Example 如果没有传入 `locale` 参数,`create()` 会为默认语言创建文档的草稿版本: 🌐 If no `locale` parameter is passed, `create()` creates the draft version of the document for the default locale: :::tip 如果在内容类型上启用了[草稿与发布](/cms/features/draft-and-publish)功能,你可以在创建文档的同时自动发布它(参见[`status` 文档`](/cms/api/document-service/status#create))。 🌐 If the [Draft & Publish](/cms/features/draft-and-publish) feature is enabled on the content-type, you can automatically publish a document while creating it (see [`status` documentation](/cms/api/document-service/status#create)). ::: ### `update()` 更新文档版本并返回它们。 🌐 Updates document versions and returns them. 语法:`update(parameters: Params) => Promise ### `delete()` 删除一个文档或其特定语言环境。 🌐 Deletes one document, or a specific locale of it. 语法:`delete(parameters: Params): Promise<{ documentId: ID, entries: Number }>` 🌐 Syntax: `delete(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### 参数 {#parameters-5} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| `documentId` | 文档 ID | | `ID` || [`locale`](/cms/api/document-service/locale#delete) | 要删除的文档的本地化版本。 | `null`
(仅删除默认语言) | 字符串, `'*'`, 或 `null` || [`filters`](/cms/api/document-service/filters) | 要使用的[筛选器](/cms/api/document-service/filters) | `null` | 对象 || [`fields`](/cms/api/document-service/fields#delete) | 要返回的[选择字段](/cms/api/document-service/fields#delete) | 所有字段
(默认未填充的除外) | 对象 || [`populate`](/cms/api/document-service/populate) | 使用附加字段[填充](/cms/api/document-service/populate)结果。 | `null` | 对象 | #### 例子 {#example-3} 🌐 Example 如果没有传递 `locale` 参数,`delete()` 只会删除文档的默认语言版本。这会删除草稿和已发布的版本: 🌐 If no `locale` parameter is passed, `delete()` only deletes the default locale version of a document. This deletes both the draft and published versions: ### `publish()` 已发布的版本是只读的,因此你无法从技术上更新文档的已发布版本。 🌐 Publishes one or multiple locales of a document. 只有在内容类型上启用了[草稿与发布](/cms/features/draft-and-publish)时,此方法才可用。 🌐 This method is only available if [Draft & Publish](/cms/features/draft-and-publish) is enabled on the content-type. 语法:`publish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` 🌐 Syntax: `publish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### 参数 {#parameters-6} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| `documentId` | 文档 ID | | `ID` || [`locale`](/cms/api/document-service/locale#publish) | 要发布的文档的语言环境 | 仅默认语言环境 | 字符串, `'*'`, 或 `null` || [`filters`](/cms/api/document-service/filters) | 使用的 [过滤器](/cms/api/document-service/filters) | `null` | 对象 || [`fields`](/cms/api/document-service/fields#publish) | 返回的 [选择字段](/cms/api/document-service/fields#publish) | 所有字段
(默认未填充的字段除外) | 对象 || [`populate`](/cms/api/document-service/populate) | 使用额外字段 [填充](/cms/api/document-service/populate) 结果 | `null` | 对象 | #### 例子 {#example-4} 🌐 Example 如果没有传递 `locale` 参数,`publish()` 只会发布文档的默认语言版本: 🌐 If no `locale` parameter is passed, `publish()` only publishes the default locale version of the document: ### `unpublish()` 取消发布文档的一个或所有语言环境版本,并返回未发布的语言环境版本数。 🌐 Unpublishes one or all locale versions of a document, and returns how many locale versions were unpublished. 只有在内容类型上启用了[草稿与发布](/cms/features/draft-and-publish)时,此方法才可用。 🌐 This method is only available if [Draft & Publish](/cms/features/draft-and-publish) is enabled on the content-type. 语法:`unpublish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` 🌐 Syntax: `unpublish(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### 参数 {#parameters-7} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| `documentId` | 文档 ID | | `ID` || [`locale`](/cms/api/document-service/locale#unpublish) | 要取消发布的文档的语言环境。 | 仅默认语言环境 | 字符串, `'*'` 或 `null` || [`filters`](/cms/api/document-service/filters) | 使用的 [过滤器](/cms/api/document-service/filters) | `null` | 对象 || [`fields`](/cms/api/document-service/fields#unpublish) | 要返回的 [选择字段](/cms/api/document-service/fields#unpublish) | 所有字段
(默认未填充的字段除外) | 对象 || [`populate`](/cms/api/document-service/populate) | 用额外字段 [填充](/cms/api/document-service/populate) 结果。 | `null` | 对象 | #### 例子 {#example-5} 🌐 Example 如果没有传入 `locale` 参数,`unpublish()` 只会取消发布文档的默认语言版本: 🌐 If no `locale` parameter is passed, `unpublish()` only unpublishes the default locale version of the document: ### `discardDraft()` 丢弃草稿数据并用已发布的版本覆盖它。 🌐 Discards draft data and overrides it with the published version. 只有在内容类型上启用了[草稿与发布](/cms/features/draft-and-publish)时,此方法才可用。 🌐 This method is only available if [Draft & Publish](/cms/features/draft-and-publish) is enabled on the content-type. 语法:`discardDraft(parameters: Params): Promise<{ documentId: ID, entries: Number }>` 🌐 Syntax: `discardDraft(parameters: Params): Promise<{ documentId: ID, entries: Number }>` #### 参数 {#parameters-8} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| `documentId` | 文档ID | | `ID` || [`locale`](/cms/api/document-service/locale#discard-draft) | 要丢弃的文档的语言环境 | 仅默认语言 | 字符串,`'*'` 或 `null` || [`filters`](/cms/api/document-service/filters) | 使用的 [过滤器](/cms/api/document-service/filters) | `null` | 对象 || [`fields`](/cms/api/document-service/fields#discarddraft) | 要返回的 [选择字段](/cms/api/document-service/fields#discarddraft) | 所有字段
(默认未填充的字段除外) | 对象 || [`populate`](/cms/api/document-service/populate) | 使用附加字段 [填充](/cms/api/document-service/populate) 结果 | `null` | 对象 | #### 例子 {#example-6} 🌐 Example 如果没有传递 `locale` 参数,`discardDraft()` 将丢弃草稿数据,并仅使用默认语言版本的已发布内容进行覆盖: 🌐 If no `locale` parameter is passed, `discardDraft()` discards draft data and overrides it with the published version only for the default locale: ### `count()` 计算与提供的参数匹配的文档数量。 🌐 Count the number of documents that match the provided parameters. 语法:`count(parameters: Params) => number` 🌐 Syntax: `count(parameters: Params) => number` #### 参数 {#parameters-9} 🌐 Parameters | 参数 | 描述 | 默认值 | 类型 ||-----------|-------------|---------|------|| [`locale`](/cms/api/document-service/locale#count) | 要计数的文档的区域设置 | 默认区域设置 | 字符串 或 `null` || [`status`](/cms/api/document-service/status#count) | _如果内容类型启用了 [草稿与发布](/cms/features/draft-and-publish)_:
发布状态,可为: | `'draft'` | `'published'` 或 `'draft'` || [`filters`](/cms/api/document-service/filters) | 要使用的 [过滤器](/cms/api/document-service/filters) | `null` | 对象 | :::note 由于已发布的文档必然也有草稿副本,因此已发布的文档仍算作具有草稿版本。 🌐 Since published documents necessarily also have a draft counterpart, a published document is still counted as having a draft version. 这意味着,即使某些文档已经发布并且在内容管理器中不再显示为“草稿”或“已修改”,使用 `status: 'draft'` 参数进行计数仍会返回符合其他参数的文档总数。目前没有方法可以阻止已发布的文档被计入统计。 🌐 This means that counting with the `status: 'draft'` parameter still returns the total number of documents matching other parameters, even if some documents have already been published and are not displayed as "draft" or "modified" in the Content Manager anymore. There currently is no way to prevent already published documents from being counted. ::: #### 例子 {#examples-2} 🌐 Examples
##### 通用示例 {#generic-example-2} 🌐 Generic example 如果未传递参数,`count()` 方法将返回默认语言环境的文档总数: ##### 统计已发布的文件 {#count-published-documents} 🌐 Count published documents 要仅计算已发布的文档,请将 `status: 'published'` 与其他参数一起传递给 `count()` 方法。 🌐 To count only published documents, pass `status: 'published'` along with other parameters to the `count()` method. 如果没有传入 `locale` 参数,将会统计默认语言环境的文档。 🌐 If no `locale` parameter is passed, documents are counted for the default locale. ##### 使用筛选条件计数文档 {#count-documents-with-filters} 🌐 Count documents with filters 任何 [filters](/cms/api/document-service/filters) 都可以传递给 `count()` 方法。 🌐 Any [filters](/cms/api/document-service/filters) can be passed to the `count()` method. 如果没有传入 `locale` 和 `status` 参数,则草稿文档(即该语言环境的所有可用文档总数,因为即使已发布的文档也被视为有草稿版本)仅会计算默认语言环境: 🌐 If no `locale` and no `status` parameter is passed, draft documents (which is the total of available documents for the locale since even published documents are counted as having a draft version) are counted only for the default locale: ```js /** * Count number of draft documents (default if status is omitted) * in English (default locale) * whose name starts with 'Pizzeria' */ strapi.documents('api::restaurant.restaurant').count({ filters: { name: { $startsWith: "Pizzeria" }}})` ``` # 使用文档服务 API 的字段 Source: https://docs.strapi.io/cms/api/document-service/fields # 文档服务 API:选择字段 {#document-service-api-selecting-fields} 🌐 Document Service API: Selecting fields 默认情况下,[文档服务 API](/cms/api/document-service) 会返回文档的所有字段,但不会填充任何字段。本页介绍如何使用 `fields` 参数仅返回查询结果中的特定字段。 🌐 By default the [Document Service API](/cms/api/document-service) returns all the fields of a document but does not populate any fields. This page describes how to use the `fields` parameter to return only specific fields with the query results. :::tip 你也可以使用 `populate` 参数来填充关系、媒体字段、组件或动态区域(参见 [`populate` 参数](/cms/api/document-service/populate) 文档)。 🌐 You can also use the `populate` parameter to populate relations, media fields, components, or dynamic zones (see the [`populate` parameter](/cms/api/document-service/populate) documentation). ::: ## 使用 `findFirst()` 查询选择字段 {#findfirst} 🌐 Select fields with `findFirst()` queries 在使用文档服务 API [查找第一个匹配参数的文档](/cms/api/document-service#findfirst) 时选择要返回的字段: 🌐 To select fields to return while [finding the first document](/cms/api/document-service#findfirst) matching the parameters with the Document Service API: ## 使用 `findMany()` 查询选择字段 {#findmany} 🌐 Select fields with `findMany()` queries 在使用文档服务 API [查找文档](/cms/api/document-service#findmany) 时选择要返回的字段: 🌐 To select fields to return while [finding documents](/cms/api/document-service#findmany) with the Document Service API: ## 使用 `create()` 查询选择字段 {#create} 🌐 Select fields with `create()` queries 在使用文档服务 API [创建文档](/cms/api/document-service#create) 时选择要返回的字段: 🌐 To select fields to return while [creating documents](/cms/api/document-service#create) with the Document Service API: ## 使用 `update()` 查询选择字段 {#update} 🌐 Select fields with `update()` queries 在使用文档服务 API [更新文档](/cms/api/document-service#update) 时选择要返回的字段: 🌐 To select fields to return while [updating documents](/cms/api/document-service#update) with the Document Service API: ## 使用 `delete()` 查询选择字段 {#delete} 🌐 Select fields with `delete()` queries 在使用文档服务 API [删除文档](/cms/api/document-service#delete) 时选择要返回的字段: 🌐 To select fields to return while [deleting documents](/cms/api/document-service#delete) with the Document Service API: ## 使用 `publish()` 查询选择字段 {#publish} 🌐 Select fields with `publish()` queries 在使用文档服务 API [发布文档](/cms/api/document-service#publish) 时选择要返回的字段: 🌐 To select fields to return while [publishing documents](/cms/api/document-service#publish) with the Document Service API: ## 选择包含 `unpublish()` 查询的字段 {#unpublish} 🌐 Select fields with `unpublish()` queries 在使用文档服务 API[取消发布文档](/cms/api/document-service#unpublish)时选择要返回的字段: 🌐 To select fields to return while [unpublishing documents](/cms/api/document-service#unpublish) with the Document Service API: ## 选择包含 `discardDraft()` 查询的字段 {#discarddraft} 🌐 Select fields with `discardDraft()` queries 使用文档服务 API 时,[丢弃文档的草稿版本](/cms/api/document-service#discarddraft) 并选择返回的字段: 🌐 To select fields to return while [discarding draft versions of documents](/cms/api/document-service#discarddraft) with the Document Service API: # 在文档服务 API 中使用过滤器 Source: https://docs.strapi.io/cms/api/document-service/filters # 文档服务 API:筛选器 {#document-service-api-filters} 🌐 Document Service API: Filters [文档服务 API](/cms/api/document-service) 提供筛选结果的功能。 🌐 The [Document Service API](/cms/api/document-service) offers the ability to filter results. 可以使用以下运算符: 🌐 The following operators are available: | 运算符 | 描述 | | --- | --- | | [`$eq`](#eq) | 相等 | | [`$eqi`](#eqi) | 相等(不区分大小写) | | [`$ne`](#ne) | 不相等 | | [`$nei`](#nei) | 不等于(不区分大小写) | | [`$lt`](#lt) | 少于 | | [`$lte`](#lte) | 小于或等于 | | [`$gt`](#gt) | 大于 | | [`$gte`](#gte) | 大于或等于 | | [`$in`](#in) | 包含在数组中 | | [`$notIn`](#notin) | 不包含在数组中 | | [`$contains`](#contains) | 包含 | | [`$notContains`](#notcontains) | 不包含 | | [`$containsi`](#containsi) | 包含(不区分大小写) | | [`$notContainsi`](#notcontainsi) | 不包含(不区分大小写) | | [`$null`](#null) | 为空 | | [`$notNull`](#notnull) | 不为空 | | [`$between`](#between) | 介于 | | [`$startsWith`](#startswith) | 以...开始 | | [`$startsWithi`](#startswithi) | 以…开头(不区分大小写) | | [`$endsWith`](#endswith) | 以...结尾 | | [`$endsWithi`](#endswithi) | 以…结尾(不区分大小写) | | [`$or`](#or) | 将过滤器组合成“或”表达式 | | [`$and`](#and) | 将过滤器组合成“与”表达式 | | [`$not`](#not) | 在“not”表达式中连接过滤器 | ## 属性运算符 {#attribute-operators} 🌐 Attribute operators
### `$not` 否定嵌套条件。 🌐 Negates the nested condition(s). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $not: { $contains: 'Hello World', }, }, }, }); ``` ### `$eq` 属性等于输入值。 🌐 Attribute equals input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $eq: 'Hello World', }, }, }); ``` `$eq`可以省略: ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: 'Hello World', }, }); ``` ### `$eqi` 属性等于输入值(不区分大小写)。 🌐 Attribute equals input value (case-insensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $eqi: 'HELLO World', }, }, }); ``` ### `$ne` 属性不等于输入值。 🌐 Attribute does not equal input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $ne: 'ABCD', }, }, }); ``` ### `$nei` 属性不等于输入值(不区分大小写)。 🌐 Attribute does not equal input value (case-insensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $nei: 'abcd', }, }, }); ``` ### `$in` 属性包含在输入列表中。 🌐 Attribute is contained in the input list. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $in: ['Hello', 'Hola', 'Bonjour'], }, }, }); ``` 在传递一个值数组时可以省略 `$in`: ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: ['Hello', 'Hola', 'Bonjour'], }, }); ``` ### `$notIn` 输入列表中不包含属性。 🌐 Attribute is not contained in the input list. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notIn: ['Hello', 'Hola', 'Bonjour'], }, }, }); ``` ### `$lt` 属性小于输入值。 🌐 Attribute is less than the input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $lt: 10, }, }, }); ``` ### `$lte` 属性小于或等于输入值。 🌐 Attribute is less than or equal to the input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $lte: 10, }, }, }); ``` ### `$gt` 属性大于输入值。 🌐 Attribute is greater than the input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $gt: 5, }, }, }); ``` ### `$gte` 属性大于或等于输入值。 🌐 Attribute is greater than or equal to the input value. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $gte: 5, }, }, }); ``` ### `$between` 属性介于两个输入值之间,包括边界(例如,`$between[1, 3]` 也会返回 `1` 和 `3`)。 🌐 Attribute is between the 2 input values, boundaries included (e.g., `$between[1, 3]` will also return `1` and `3`). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { rating: { $between: [1, 20], }, }, }); ``` ### `$contains` 属性包含输入值(区分大小写)。 🌐 Attribute contains the input value (case-sensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $contains: 'Hello', }, }, }); ``` ### `$notContains` 属性不包含输入值(区分大小写)。 🌐 Attribute does not contain the input value (case-sensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notContains: 'Hello', }, }, }); ``` ### `$containsi` 属性包含输入值。`$containsi`不区分大小写,而[$contains](#contains)区分大小写。 🌐 Attribute contains the input value. `$containsi` is not case-sensitive, while [$contains](#contains) is. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $containsi: 'hello', }, }, }); ``` ### `$notContainsi` 属性不包含输入值。`$notContainsi` 不区分大小写,而 [$notContains](#notcontains) 区分大小写。 🌐 Attribute does not contain the input value. `$notContainsi` is not case-sensitive, while [$notContains](#notcontains) is. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notContainsi: 'hello', }, }, }); ``` ### `$startsWith` 属性以输入值开头(区分大小写)。 🌐 Attribute starts with input value (case-sensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $startsWith: 'ABCD', }, }, }); ``` ### `$startsWithi` 属性以输入值开头(不区分大小写)。 🌐 Attribute starts with input value (case-insensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $startsWithi: 'ABCD', // will return the same as filtering with 'abcd' }, }, }); ``` ### `$endsWith` 属性以输入值结尾(区分大小写)。 🌐 Attribute ends with input value (case-sensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $endsWith: 'ABCD', }, }, }); ``` ### `$endsWithi` 属性以输入值结尾(不区分大小写)。 🌐 Attribute ends with input value (case-insensitive). **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $endsWith: 'ABCD', // will return the same as filtering with 'abcd' }, }, }, }); ``` ### `$null` 属性是 `null`。 🌐 Attribute is `null`. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $null: true, }, }, }); ``` ### `$notNull` 属性不是 `null`。 🌐 Attribute is not `null`. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: { $notNull: true, }, }, }); ``` ## 逻辑运算符 {#logical-operators} 🌐 Logical operators ### `$and` 所有嵌套条件必须是 `true`。 🌐 All nested conditions must be `true`. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $and: [ { title: 'Hello World', }, { createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, ], }, }); ``` `$and` 在传递带有嵌套条件的对象时将被隐式使用: ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { title: 'Hello World', createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, }); ``` ### `$or` 一个或多个嵌套条件必须是 `true`。 🌐 One or many nested conditions must be `true`. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $or: [ { title: 'Hello World', }, { createdAt: { $gt: '2021-11-17T14:28:25.843Z' }, }, ], }, }); ``` ### `$not` 否定嵌套条件。 🌐 Negates the nested conditions. **示例** ```js const entries = await strapi.documents('api::article.article').findMany({ filters: { $not: { title: 'Hello World', }, }, }); ``` :::note `$not` 可以用作: - 一个逻辑运算符(例如在 `filters: { $not: { // conditions… }}` 中) - [属性操作符](#not)(例如在 `filters: { attribute-name: $not: { … } }` 中)。 ::: :::tip `$and`、`$or` 和 `$not` 操作符可以嵌套在另一个 `$and`、`$or` 或 `$not` 操作符中。 ::: # 在文档服务 API 中使用区域参数 Source: https://docs.strapi.io/cms/api/document-service/locale # 文档服务 API:使用 `locale` 参数 {#document-service-api-using-the-locale-parameter} 🌐 Document Service API: Using the `locale` parameter 默认情况下,[Document Service API](/cms/api/document-service) 返回文档的默认语言版本(默认为'en',即英语版本,除非应用已设置了其他默认语言,详见[国际化(i18n)功能](/cms/features/internationalization))。本页面描述了如何使用 `locale` 参数仅获取或操作特定语言的数据。 🌐 By default the [Document Service API](/cms/api/document-service) returns the default locale version of documents (which is 'en', i.e. the English version, unless another default locale has been set for the application, see [Internationalization (i18n) feature](/cms/features/internationalization)). This page describes how to use the `locale` parameter to get or manipulate data only for specific locales. ## 获取带有 `findOne()` 的本地化版本 {#find-one} 🌐 Get a locale version with `findOne()` 如果传入 `locale`,文档服务 API 的 [`findOne()` 方法](/cms/api/document-service#findone) 将返回该语言环境的文档版本: 🌐 If a `locale` is passed, the [`findOne()` method](/cms/api/document-service#findone) of the Document Service API returns the version of the document for this locale: 如果没有传递 `status` 参数,则默认返回 `draft` 版本。 🌐 If no `status` parameter is passed, the `draft` version is returned by default. ## 获取带有 `findFirst()` 的本地化版本 {#find-first} 🌐 Get a locale version with `findFirst()` 要在使用文档服务 API [查找第一个](/cms/api/document-service#findfirst) 与参数匹配的文档时返回特定区域设置: 🌐 To return a specific locale while [finding the first document](/cms/api/document-service#findfirst) matching the parameters with the Document Service API: 如果没有传递 `status` 参数,则默认返回 `draft` 版本。 🌐 If no `status` parameter is passed, the `draft` version is returned by default. ## 使用 `findMany()` 获取本地化版本 {#find-many} 🌐 Get locale versions with `findMany()` 当将 `locale` 传递给文档服务 API 的 [`findMany()` 方法](/cms/api/document-service#findmany) 时,响应将返回所有具有此语言环境的文档。 🌐 When a `locale` is passed to the [`findMany()` method](/cms/api/document-service#findmany) of the Document Service API, the response will return all documents that have this locale available. 如果没有传递 `status` 参数,则默认返回 `draft` 版本。 🌐 If no `status` parameter is passed, the `draft` versions are returned by default.
解释: 给定以下 4 个具有不同语言环境的文档: 🌐 Given the following 4 documents that have various locales: - 文件A: - en - `fr` - it - 文件 B: - en - it - 文件 C: - `fr` - 文件 D: - `fr` - it `findMany({ locale: 'fr' })` 只会返回那些有 `‘fr’` 语言版本的文档的草稿版本,即文档 A、C 和 D。
## `create()` 为一个区域创建文档 {#create} 🌐 `create()` a document for a locale 要为特定区域创建文档,请将 `locale` 作为参数传递给文档服务 API 的 [`create` 方法](/cms/api/document-service#create): 🌐 To create a document for specific locale, pass the `locale` as a parameter to the [`create` method](/cms/api/document-service#create) of the Document Service API: ## `update()` 本地化版本 {#update} 🌐 `update()` a locale version 要仅更新文档的特定语言版本,请将 `locale` 参数传递给文档服务 API 的 [`update()` 方法](/cms/api/document-service#update): 🌐 To update only a specific locale version of a document, pass the `locale` parameter to the [`update()` method](/cms/api/document-service#update) of the Document Service API: ## `delete()` 语言区域版本 {#delete} 🌐 `delete()` locale versions 使用 Document Service API 的 [`delete()` 方法](/cms/api/document-service#delete) 的 `locale` 参数仅删除某些语言版本。除非传入特定的 `status` 参数,否则这将删除草稿和已发布版本。 🌐 Use the `locale` parameter with the [`delete()` method](/cms/api/document-service#delete) of the Document Service API to delete only some locales. Unless a specific `status` parameter is passed, this deletes both the draft and published versions. ### 删除一个语言版本 {#delete-a-locale-version} 🌐 Delete a locale version 要删除文档的特定语言环境版本: 🌐 To delete a specific locale version of a document: ### 删除所有语言版本 {#delete-all-locale-versions} 🌐 Delete all locale versions `*` 通配符由 `locale` 参数支持,可用于删除文档的所有语言版本: 🌐 The `*` wildcard is supported by the `locale` parameter and can be used to delete all locale versions of a document: ## `publish()` 语言版本 {#publish} 🌐 `publish()` locale versions 要使用文档服务 API 的 [`publish()` 方法](/cms/api/document-service#publish) 仅发布文档的特定语言版本,请将 `locale` 作为参数传递: 🌐 To publish only specific locale versions of a document with the [`publish()` method](/cms/api/document-service#publish) of the Document Service API, pass `locale` as a parameter: ### 发布本地化版本 {#publish-a-locale-version} 🌐 Publish a locale version 要发布文档的特定语言环境版本: 🌐 To publish a specific locale version of a document: ### 发布所有语言版本 {#publish-all-locale-versions} 🌐 Publish all locale versions `*` 通配符由 `locale` 参数支持,用于发布文档的所有语言版本: 🌐 The `*` wildcard is supported by the `locale` parameter to publish all locale versions of a document: ## `unpublish()` 语言版本 {#unpublish} 🌐 `unpublish()` locale versions 要使用文档服务 API 的 [`unpublish()` 方法](/cms/api/document-service#unpublish) 仅发布文档的特定语言版本,请将 `locale` 作为参数传递: 🌐 To publish only specific locale versions of a document with the [`unpublish()` method](/cms/api/document-service#unpublish) of the Document Service API, pass `locale` as a parameter: ### 取消发布本地版本 {#unpublish-a-locale-version} 🌐 Unpublish a locale version 要取消发布文档的特定语言版本,请将 `locale` 作为参数传递给 `unpublish()`: 🌐 To unpublish a specific locale version of a document, pass the `locale` as a parameter to `unpublish()`: ### 取消发布所有语言版本 {#unpublish-all-locale-versions} 🌐 Unpublish all locale versions `*` 通配符由 `locale` 参数支持,用于取消发布文档的所有语言版本: 🌐 The `*` wildcard is supported by the `locale` parameter, to unpublish all locale versions of a document: ## `discardDraft()` 用于本地化版本 {#discard-draft} 🌐 `discardDraft()` for locale versions 要仅丢弃某些语言版本文档的草稿数据,使用文档服务 API 的 [`discardDraft()` 方法](/cms/api/document-service#discarddraft),传递 `locale` 作为参数: 🌐 To discard draft data only for some locales versions of a document with the [`discardDraft()` method](/cms/api/document-service#discarddraft) of the Document Service API, pass `locale` as a parameter: ### 丢弃本地化版本的草稿 {#discard-draft-for-a-locale-version} 🌐 Discard draft for a locale version 要放弃文档特定语言版本的草稿数据,并用该语言版本的已发布数据覆盖它,请将 `locale` 作为参数传递给 `discardDraft()`: 🌐 To discard draft data for a specific locale version of a document and override it with data from the published version for this locale, pass the `locale` as a parameter to `discardDraft()`: ### 丢弃所有语言版本的草稿 {#discard-drafts-for-all-locale-versions} 🌐 Discard drafts for all locale versions `*` 通配符由 `locale` 参数支持,用于丢弃文档的所有区域版本的草稿数据,并用已发布版本的数据替换它们: 🌐 The `*` wildcard is supported by the `locale` parameter, to discard draft data for all locale versions of a document and replace them with the data from the published versions: ## `count()` 个本地化文档 {#count} 🌐 `count()` documents for a locale 要统计特定语言环境的文档,请将 `locale` 与其他参数一起传递给文档服务 API 的 [`count()` 方法](/cms/api/document-service#count)。 🌐 To count documents for a specific locale, pass the `locale` along with other parameters to the [`count()` method](/cms/api/document-service#count) of the Document Service API. 如果没有传递 `status` 参数,则统计草稿文档(即该语言环境下可用文档的总数,因为即使已发布的文档也会被计为有草稿版本): 🌐 If no `status` parameter is passed, draft documents are counted (which is the total of available documents for the locale since even published documents are counted as having a draft version): ```js // Count number of published documents in French strapi.documents('api::restaurant.restaurant').count({ locale: 'fr' }); ``` # 扩展文档服务行为 Source: https://docs.strapi.io/cms/api/document-service/middlewares # 文档服务 API:中间件 {#document-service-api-middlewares} 🌐 Document Service API: Middlewares [文档服务 API](/cms/api/document-service) 提供了通过中间件扩展其行为的能力。 🌐 The [Document Service API](/cms/api/document-service) offers the ability to extend its behavior thanks to middlewares. 文档服务中间件允许你在方法运行之前和/或之后执行操作。 🌐 Document Service middlewares allow you to perform actions before and/or after a method runs.
Simplified Strapi backend diagram with controllers highlighted
该图表示请求在 Strapi 后端传输的简化版本,并突出了文档服务。后端自定义介绍页面包括一个完整的、 交互式图表
## 注册中间件 {#registering-a-middleware} 🌐 Registering a middleware 语法:`strapi.documents.use(middleware)` 🌐 Syntax: `strapi.documents.use(middleware)` ### 参数 {#parameters} 🌐 Parameters 中间件是一种接收上下文和下一个函数的函数。 🌐 A middleware is a function that receives a context and a next function. 语法:`(context, next) => ReturnType` 🌐 Syntax: `(context, next) => ReturnType` | 参数 | 描述 | 类型 ||-----------|---------------------------------------|------------|| `context` | 中间件上下文 | `Context` || `next` | 调用堆栈中的下一个中间件 | `function` | #### `context` | 参数 | 描述 | 类型 ||---------------|--------------------------------------------------------------------------------------|---------------|| `action` | 正在运行的方法([查看可用方法](/cms/api/document-service)) | `string` || `params` | 方法参数([查看可用方法](/cms/api/document-service)) | `Object` || `uid` | 内容类型唯一标识 | `string` || `contentType` | 内容类型 | `ContentType` |
示例: 以下示例显示了根据调用的方法,`context` 可能包含的内容: 🌐 The following examples show what `context` might include depending on the method called:
#### `next` `next` 是一个没有参数的函数,它调用堆栈中的下一个中间件并返回其响应。 **示例** ```js strapi.documents.use((context, next) => { return next(); }); ``` ### 在哪里注册 {#where-to-register} 🌐 Where to register 一般来说,你应该在 Strapi 注册阶段注册你的中间件。 🌐 Generaly speaking you should register your middlewares during the Strapi registration phase. #### 用户 {#users} 🌐 Users 中间件必须在通用的 `register()` 生命周期方法中注册: 🌐 The middleware must be registered in the general `register()` lifecycle method: ```js title="/src/index.js|ts" module.exports = { register({ strapi }) { strapi.documents.use((context, next) => { // your logic return next(); }); }, // bootstrap({ strapi }) {}, // destroy({ strapi }) {}, }; ``` #### 插件开发者 {#plugin-developers} 🌐 Plugin developers 中间件必须在插件的 `register()` 生命周期方法中注册: 🌐 The middleware must be registered in the plugin's `register()` lifecycle method: ```js title="/(plugin-root-folder)/strapi-server.js|ts" module.exports = { register({ strapi }) { strapi.documents.use((context, next) => { // your logic return next(); }); }, // bootstrap({ strapi }) {}, // destroy({ strapi }) {}, }; ``` ## 实现中间件 {#implementing-a-middleware} 🌐 Implementing a middleware 在实现中间件时,总是要返回来自 `next()` 的响应。 如果不这样做,将会导致 Strapi 应用出错。 🌐 When implementing a middleware, always return the response from `next()`. Failing to do this will break the Strapi application. ### 例子 {#examples} 🌐 Examples ```js const applyTo = ['api::article.article']; strapi.documents.use((context, next) => { // Only run for certain content types if (!applyTo.includes(context.uid)) { return next(); } // Only run for certain actions if (['create', 'update'].includes(context.action)) { context.params.data.fullName = `${context.params.data.firstName} ${context.params.data.lastName}`; } const result = await next(); // do something with the result before returning it return result }); ```
:::strapi Lifecycle hooks 文档服务 API 会根据调用的方法触发各种数据库生命周期钩子。完整参考请参见 [文档服务 API:生命周期钩子](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service#table)。 🌐 The Document Service API triggers various database lifecycle hooks based on which method is called. For a complete reference, see [Document Service API: Lifecycle hooks](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service#table). ::: # 使用 Document Service API 的 Populate Source: https://docs.strapi.io/cms/api/document-service/populate # 文档服务 API:填充字段 {#document-service-api-populating-fields} 🌐 Document Service API: Populating fields 默认情况下,[文档服务 API](/cms/api/document-service) 不会填充任何关系、媒体字段、组件或动态区域。本页介绍如何使用 `populate` 参数来填充特定字段。 🌐 By default the [Document Service API](/cms/api/document-service) does not populate any relations, media fields, components, or dynamic zones. This page describes how to use the `populate` parameter to populate specific fields. :::tip 你也可以使用 `select` 参数仅返回查询结果中的特定字段(参见 [`select` 参数](/cms/api/document-service/fields) 文档)。 🌐 You can also use the `select` parameter to return only specific fields with the query results (see the [`select` parameter](/cms/api/document-service/fields) documentation). ::: :::caution 如果安装了“用户与权限”插件,则必须为正在填充的内容类型启用 `find` 权限。如果某个角色无法访问某个内容类型,则该内容类型将不会被填充。 🌐 If the Users & Permissions plugin is installed, the `find` permission must be enabled for the content-types that are being populated. If a role doesn't have access to a content-type it will not be populated. ::: ## 关系与媒体字段 {#relations-and-media-fields} 🌐 Relations and media fields 查询可以接受一个 `populate` 参数来明确指定要填充的字段,语法选项示例如下。 🌐 Queries can accept a `populate` parameter to explicitly define which fields to populate, with the following syntax option examples. ### 为所有关系填充 1 级 {#populate-1-level-for-all-relations} 🌐 Populate 1 level for all relations 要为所有关系填充一层深度,请将 `*` 通配符与 `populate` 参数结合使用: 🌐 To populate one-level deep for all relations, use the `*` wildcard in combination with the `populate` parameter: ### 为特定关系填充 1 级 {#populate-1-level-for-specific-relations} 🌐 Populate 1 level for specific relations 要填充特定的一层深度的关系,请在 `populate` 数组中传入关系名称: 🌐 To populate specific relations one-level deep, pass the relation names in a `populate` array: ### 为特定关系填充多层数据 {#populate-several-levels-deep-for-specific-relations} 🌐 Populate several levels deep for specific relations 要填充多层的特定关联,请使用带有 `populate` 的对象格式: 🌐 To populate specific relations several levels deep, use the object format with `populate`: ## 组件与动态区域 {#components--dynamic-zones} 🌐 Components & Dynamic Zones 组件的填充方式与关系相同: 🌐 Components are populated the same way as relations: 动态区域本质上是高度动态的内容结构。要填充动态区域,你必须使用 `on` 属性为每个组件定义填充查询。 🌐 Dynamic zones are highly dynamic content structures by essence. To populate a dynamic zone, you must define per-component populate queries using the `on` property. ## 正在用 `create()` 填充 {#populating-with-create} 🌐 Populating with `create()` 要在创建文档时填充: 🌐 To populate while creating documents: ## 正在用 `update()` 填充 {#populating-with-update} 🌐 Populating with `update()` 要在更新文档时填充: 🌐 To populate while updating documents: ## 正在用 `publish()` 填充 {#populating-with-publish} 🌐 Populating with `publish()` 在发布文档时进行填充(与 `unpublish()` 和 `discardDraft()` 的行为相同): 🌐 To populate while publishing documents (same behavior with `unpublish()` and `discardDraft()`): # 在文档服务 API 中使用排序和分页 Source: https://docs.strapi.io/cms/api/document-service/sort-pagination # 文档服务 API:结果的排序和分页 {#document-service-api-sorting-and-paginating-results} 🌐 Document Service API: Sorting and paginating results [文档服务 API](/cms/api/document-service) 提供对查询结果进行排序和分页的功能。 🌐 The [Document Service API](/cms/api/document-service) offers the ability to sort and paginate query results. ## 排序 {#sort} 🌐 Sort 要对文档服务 API 返回的结果进行排序,请在查询中包含 `sort` 参数。 🌐 To sort results returned by the Document Service API, include the `sort` parameter with queries. ### 按单个字段排序 {#sort-on-a-single-field} 🌐 Sort on a single field 要根据单个字段对结果进行排序: 🌐 To sort results based on a single field: ### 按多个字段排序 {#sort-on-multiple-fields} 🌐 Sort on multiple fields 要对多个字段进行排序,请将它们全部传递到一个数组中: 🌐 To sort on multiple fields, pass them all in an array: ## 分页 {#pagination} 🌐 Pagination 要对结果进行分页,请传递 `limit` 和 `start` 参数: 🌐 To paginate results, pass the `limit` and `start` parameters: # 在文档服务 API 中使用草稿与发布 Source: https://docs.strapi.io/cms/api/document-service/status # 文档服务 API:草稿与发布的使用 {#document-service-api-usage-with-draft--publish} 🌐 Document Service API: Usage with Draft & Publish 默认情况下,当启用 [Draft & Publish](/cms/features/draft-and-publish) 功能时,[Document Service API](/cms/api/document-service) 会返回文档的草稿版本。此页面描述了如何使用 `status` 参数来: 🌐 By default the [Document Service API](/cms/api/document-service) returns the draft version of a document when the [Draft & Publish](/cms/features/draft-and-publish) feature is enabled. This page describes how to use the `status` parameter to: - 返回文档的已发布版本, - 根据文档的状态计数文档, - 并在创建或更新文档时直接发布文档。 :::note 将 `{ status: 'draft' }` 传递给文档服务 API 查询返回的结果与未传递任何 `status` 参数时相同。 🌐 Passing `{ status: 'draft' }` to a Document Service API query returns the same results as not passing any `status` parameter. ::: ## 获取已发布的版本与 `findOne()` {#find-one} 🌐 Get the published version with `findOne()` `findOne()` 查询默认返回文档的草稿版本。 要在使用文档服务 API [查找特定文档](/cms/api/document-service#findone) 时返回已发布的版本,请传递 `status: 'published'`: 🌐 To return the published version while [finding a specific document](/cms/api/document-service#findone) with the Document Service API, pass `status: 'published'`: ## 获取带有 `findFirst()` {#find-first} 的已发布版本 🌐 Get the published version with `findFirst()` `findFirst()` 查询默认返回文档的草稿版本。 要在使用文档服务 API[查找第一个文档](/cms/api/document-service#findfirst)时返回已发布的版本,请传递 `status: 'published'`: 🌐 To return the published version while [finding the first document](/cms/api/document-service#findfirst) with the Document Service API, pass `status: 'published'`: ## 获取已发布的版本与 `findMany()` {#find-many} 🌐 Get the published version with `findMany()` `findMany()` 查询默认返回文档的草稿版本。 在使用文档服务 API [查找文档](/cms/api/document-service#findmany) 时,要返回已发布的版本,请传递 `status: 'published'`: 🌐 To return the published version while [finding documents](/cms/api/document-service#findmany) with the Document Service API, pass `status: 'published'`: ## `count()` 仅草稿或已发布版本 {#count} 🌐 `count()` only draft or published versions 在使用文档服务 API [计数文档](/cms/api/document-service#count) 时,如果只考虑文档的草稿或已发布版本,请传递相应的 `status` 参数: 🌐 To take into account only draft or published versions of documents while [counting documents](/cms/api/document-service#count) with the Document Service API, pass the corresponding `status` parameter: ```js // Count draft documents (also actually includes published documents) const draftsCount = await strapi.documents("api::restaurant.restaurant").count({ status: 'draft' }); ``` ```js // Count only published documents const publishedCount = await strapi.documents("api::restaurant.restaurant").count({ status: 'published' }); ``` :::note 由于已发布的文档必然也有草稿副本,因此已发布的文档仍算作具有草稿版本。 🌐 Since published documents necessarily also have a draft counterpart, a published document is still counted as having a draft version. 这意味着,即使某些文档已经发布并且在内容管理器中不再显示为“草稿”或“已修改”,使用 `status: 'draft'` 参数进行计数仍会返回符合其他参数的文档总数。目前没有方法可以阻止已发布的文档被计入统计。 🌐 This means that counting with the `status: 'draft'` parameter still returns the total number of documents matching other parameters, even if some documents have already been published and are not displayed as "draft" or "modified" in the Content Manager anymore. There currently is no way to prevent already published documents from being counted. ::: ## 创建草稿并发布它 {#create} 🌐 Create a draft and publish it 要在创建文档时自动发布它,请将 `status: 'published'` 添加到传递给 `create()` 的参数中: 🌐 To automatically publish a document while creating it, add `status: 'published'` to parameters passed to `create()`: ## 更新草稿并发布它 {#update} 🌐 Update a draft and publish it 要在更新文档时自动发布它,请将 `status: 'published'` 添加到传递给 `update()` 的参数中: 🌐 To automatically publish a document while updating it, add `status: 'published'` to parameters passed to `update()`: # GraphQL API Source: https://docs.strapi.io/cms/api/graphql # GraphQL API GraphQL API 允许通过 Strapi 的 [GraphQL 插件](/cms/plugins/graphql) 对 [内容类型](/cms/backend-customization/models#content-types) 执行查询和变更。结果可以被 [过滤](#filters)、[排序](#sorting) 和 [分页](#pagination)。 🌐 The GraphQL API allows performing queries and mutations to interact with the [content-types](/cms/backend-customization/models#content-types) through Strapi's [GraphQL plugin](/cms/plugins/graphql). Results can be [filtered](#filters), [sorted](#sorting) and [paginated](#pagination). :::prerequisites 要使用 GraphQL API,请安装 [GraphQL](/cms/plugins/graphql) 插件: 🌐 To use the GraphQL API, install the [GraphQL](/cms/plugins/graphql) plugin: ::: 安装完成后,GraphQL playground 可通过 `/graphql` URL 访问,并可用于交互式构建查询和变更操作,以及阅读针对你的内容类型定制的文档: 🌐 Once installed, the GraphQL playground is accessible at the `/graphql` URL and can be used to interactively build your queries and mutations and read documentation tailored to your content-types: #### 获取关系 {#fetch-relations} 🌐 Fetch relations 你可以在你的扁平查询或你的 ::: ### 获取媒体字段 {#fetch-media-fields} 🌐 Fetch media fields 媒体字段内容的获取方式与其他属性一样。 🌐 Media fields content is fetched just like other attributes. 以下示例获取“Restaurants”内容类型中附加到每个文档的每个 `cover` 媒体字段的 `url` 属性值: 🌐 The following example fetches the `url` attribute value for each `cover` media field attached to each document from the "Restaurants" content-type: ```graphql { restaurants { images { documentId url } } } ``` 对于多个媒体字段,你可以使用扁平查询或 ### 获取组件 {#fetch-components} 🌐 Fetch components 组件内容的获取方式与其他属性一样。 🌐 Components content is fetched just like other attributes. 以下示例获取每个文档中添加的每个 `closingPeriod` 组件的 `label`、`start_date` 和 `end_date` 属性值,这些文档来自“餐馆”内容类型: 🌐 The following example fetches the `label`, `start_date`, and `end_date` attributes values for each `closingPeriod` component added to each document from the "Restaurants" content-type: ```graphql { restaurants { closingPeriod { label start_date end_date } } } ``` ### 获取动态区域数据 {#fetch-dynamic-zone-data} 🌐 Fetch dynamic zone data 动态区域是在 GraphQL 中的联合类型,因此你需要使用 ```graphql title="Simple examples for membership operators (in, notIn)" # in - returns restaurants with category either "pizza" or "burger" { restaurants(filters: { category: { in: ["pizza", "burger"] } }) { name } } # notIn - returns restaurants whose category is neither "pizza" nor "burger" { restaurants(filters: { category: { notIn: ["pizza", "burger"] } }) { name } } ``` ```graphql title="Simple examples for null checks operators (null, notNull)" # null - returns restaurants where description is null { restaurants(filters: { description: { null: true } }) { name } } # notNull - returns restaurants where description is not null { restaurants(filters: { description: { notNull: true } }) { name } } ``` ```graphql title="Simple examples for logical operators (and, or, not)" # and - both category must be "pizza" AND averagePrice must be < 20 { restaurants(filters: { and: [ { category: { eq: "pizza" } }, { averagePrice: { lt: 20 } } ] }) { name } } # or - category is "pizza" OR category is "burger" { restaurants(filters: { or: [ { category: { eq: "pizza" } }, { category: { eq: "burger" } } ] }) { name } } # not - category must NOT be "pizza" { restaurants(filters: { not: { category: { eq: "pizza" } } }) { name } } ``` ```graphql title="Example with nested logical operators: use and, or, and not to find pizzerias under 20 euros" { restaurants( filters: { and: [ { not: { averagePrice: { gte: 20 } } } { or: [ { name: { eq: "Pizzeria" } } { name: { startsWith: "Pizzeria" } } ] } ] } ) { documentId name averagePrice } } ``` ### 获取特定语言环境的文档 {#locale-fetch} 🌐 Fetch a document in a specific locale 要获取特定区域的文档 ### 创建一个新的本地化文档 {#locale-create} 🌐 Create a new localized document `locale` 字段可以传递以创建针对特定语言环境的本地化文档 # OpenAPI 规范 Source: https://docs.strapi.io/cms/api/openapi # OpenAPI 规范生成 {#openapi-specification-generation} 🌐 OpenAPI specification generation Strapi 提供了一个命令行工具来为你的应用生成 你还可以传递一个可选的 `--output` 参数来指定路径和文件名,如下面的示例所示: 🌐 You can also path an optional `--output` argument to specify the path and filename, as in the following example: ### 规范结构和内容 {#specification-structure-and-content} 🌐 Specification structure and content 生成的 OpenAPI 规范遵循
生成的 OpenAPI 规范包含 Strapi 应用中所有可用的 API 端点,以及有关这些端点的信息,例如: 🌐 The generated OpenAPI specification includes all available API endpoints in your Strapi application, and information about these endpoints, such as the following: - 适用于所有内容类型的 CRUD 操作 - 应用中定义的自定义 API 路由 - 用于用户管理的身份验证端点 - 用于媒体处理的文件上传端点 - 已安装插件的插件端点 ## 与 Swagger UI 集成 {#integrating-with-swagger-ui} 🌐 Integrating with Swagger UI 通过以下步骤,你可以快速生成一个与 [Swagger UI](https://swagger.io/) 兼容的页面: 🌐 With the following steps you can quickly generate a [Swagger UI](https://swagger.io/)-compatible page: 1. 生成规范: 2. 使用以下代码更新 [ `/config/middlewares.js` 配置文件](/cms/configurations/middlewares): 这将确保来自 的 Swagger UI 显示不会被由[安全中间件](/cms/configurations/middlewares#security)处理的 Strapi CSP 策略阻止。 3. 在你的 Strapi 项目中创建一个 `public/openapi.html` 文件来显示 Swagger UI,代码如下: ```html API Documentation
``` 4. 使用 `yarn develop` 或 `npm run develop` 重新启动 Strapi 服务器,然后访问 `/openapi.html` 页面。应该会显示 Swagger UI: ![使用 Strapi OpenAPI 规范的 Swagger UI 示例](/img/assets/apis/swagger-open-api.png) # REST API参考 Source: https://docs.strapi.io/cms/api/rest # REST API参考 {#rest-api-reference} 🌐 REST API reference REST API 允许通过 API 端点访问 [内容类型](/cms/backend-customization/models)。Strapi 在创建内容类型时会自动创建 [API 端点](#endpoints)。在查询 API 端点时可以使用 [API 参数](/cms/api/rest/parameters) 来优化结果。 🌐 The REST API allows accessing the [content-types](/cms/backend-customization/models) through API endpoints. Strapi automatically creates [API endpoints](#endpoints) when a content-type is created. [API parameters](/cms/api/rest/parameters) can be used when querying API endpoints to refine the results. 本节文档是针对内容类型的 REST API 参考。我们还提供了针对特定用例的[指南](/cms/api/rest/guides/intro)。 🌐 This section of the documentation is for the REST API reference for content-types. We also have [guides](/cms/api/rest/guides/intro) available for specific use cases. :::prerequisites 所有内容类型默认都是私有的,需要将其设为公开,或者查询需要使用适当权限进行认证。有关更多详细信息,请参阅[快速入门指南](/cms/quick-start#step-4-set-roles--permissions)、[用户与权限功能](/cms/features/users-permissions#roles)用户指南,以及[API 令牌配置文档](/cms/features/api-tokens)。 🌐 All content types are private by default and need to be either made public or queries need to be authenticated with the proper permissions. See the [Quick Start Guide](/cms/quick-start#step-4-set-roles--permissions), the user guide for the [Users & Permissions feature](/cms/features/users-permissions#roles), and [API tokens configuration documentation](/cms/features/api-tokens) for more details. ::: :::note 默认情况下,REST API 响应仅包含顶层字段,不会填充任何关系、媒体字段、组件或动态区域。使用 [`populate` 参数](/cms/api/rest/populate-select) 来填充特定字段。确保为要填充的关系的字段授予查找权限。 🌐 By default, the REST API responses only include top-level fields and does not populate any relations, media fields, components, or dynamic zones. Use the [`populate` parameter](/cms/api/rest/populate-select) to populate specific fields. Ensure that the find permission is given to the field(s) for the relation(s) you populate. ::: :::strapi Strapi Client [Strapi 客户端](/cms/api/client) 库简化了与你的 Strapi 后端的交互,提供了一种获取、创建、更新和删除内容的方式。 🌐 The [Strapi Client](/cms/api/client) library simplifies interactions with your Strapi back end, providing a way to fetch, create, update, and delete content. ::: ## 端点 {#endpoints} 🌐 Endpoints 对于每个 Content-Type,会自动生成以下端点: 🌐 For each Content-Type, the following endpoints are automatically generated:
复数 API ID 与 单数 API ID: 在下表中: 🌐 In the following tables: - `:singularApiId` 指内容类型中“API ID(单数)”字段的值, - 而 `:pluralApiId` 指的是内容类型的“API ID(复数)”字段的值。 这些值是在内容类型构建器中创建内容类型时定义的,并且可以在管理面板编辑内容类型时找到(参见 [用户指南](/cms/features/content-type-builder#creating-content-types))。例如,对于“文章”内容类型,默认情况下: 🌐 These values are defined when creating a content-type in the Content-Type Builder, and can be found while editing a content-type in the admin panel (see [User Guide](/cms/features/content-type-builder#creating-content-types)). For instance, by default, for an "Article" content-type: - `:singularApiId` 将是 `article` - `:pluralApiId` 将是 `articles`
端点的真实世界示例: 以下端点示例取自
:::strapi Upload API 上传包(为[媒体库功能](/cms/features/media-library)提供支持)有一个特定的 API,可通过其[`/api/upload`端点](/cms/api/rest/upload)访问。 🌐 The Upload package (which powers the [Media Library feature](/cms/features/media-library)) has a specific API accessible through its [`/api/upload` endpoints](/cms/api/rest/upload). ::: :::note [组件](/cms/backend-customization/models#components-json) 没有 API 端点。 ::: ## 请求 {#requests} 🌐 Requests :::strapi Strapi 5 vs. Strapi v4 Strapi 5 的内容 API 与 Strapi v4 有 2 个主要区别: 🌐 Strapi 5's Content API includes 2 major differences with Strapi v4: - 响应格式已被扁平化,这意味着属性不再嵌套在 `data.attributes` 对象中,而是可以直接在 `data` 对象的第一层访问(例如,内容类型的“title”属性可以使用 `data.title` 访问)。 - Strapi 5 现在使用 **文档** ### 获取文档 {#get} 🌐 Get a document 通过 `documentId` 返回文档。 🌐 Returns a document by `documentId`. :::strapi Strapi 5 vs. Strapi v4 在 Strapi 5 中,特定文档可以通过其 `documentId` 来访问。 🌐 In Strapi 5, a specific document is reached by its `documentId`. ::: ### 创建文档 {#create} 🌐 Create a document 创建一个文档并返回其值。 🌐 Creates a document and returns its value. 如果安装了[国际化 (i18n) 插件](/cms/features/internationalization),则可以使用 POST 请求向 REST API [创建本地化文档](/cms/api/rest/locale#rest-delete)。 🌐 If the [Internationalization (i18n) plugin](/cms/features/internationalization) is installed, it's possible to use POST requests to the REST API to [create localized documents](/cms/api/rest/locale#rest-delete). :::note 在创建文档时,你可以定义其关系及其顺序(有关更多详细信息,请参见[通过 REST API 管理关系](/cms/api/rest/relations.md))。 🌐 While creating a document, you can define its relations and their order (see [Managing relations through the REST API](/cms/api/rest/relations.md) for more details). ::: ### 更新文档 {#update} 🌐 Update a document 通过 `id` 部分更新文档并返回其值。 🌐 Partially updates a document by `id` and returns its value. 发送一个 `null` 值以清除字段。 🌐 Send a `null` value to clear fields. :::note NOTES * 即使安装了[国际化 (i18n) 插件](/cms/features/internationalization),目前仍然无法[更新文档的语言环境](/cms/api/rest/locale#rest-update)。 * 在更新文档时,你可以定义其关系及其顺序(有关更多详细信息,请参见[通过 REST API 管理关系](/cms/api/rest/relations))。 ::: ### 删除文档 {#delete} 🌐 Delete a document 删除文档。 🌐 Deletes a document. `DELETE` 请求在成功时仅发送 204 HTTP 状态码,并且不会在响应体中返回任何数据。 # 过滤器 Source: https://docs.strapi.io/cms/api/rest/filters # REST API:过滤器 {#rest-api-filters} 🌐 REST API: Filters [REST API](/cms/api/rest) 提供了使用其 ["获取条目"](/cms/api/rest#get-all) 方法筛选结果的能力。
使用可选的 Strapi 功能可以提供更多筛选条件: - 如果在某个内容类型上启用了[国际化 (i18n) 插件](/cms/features/internationalization),就可以按语言环境进行过滤。 - 如果启用了 [Draft & Publish](/cms/features/draft-and-publish),可以根据 `published`(默认)或 `draft` 状态进行筛选。 :::tip
JavaScript 查询(使用 qs 库构建): ## 示例:查找 ID 为 3、6、8 的多家餐厅 {#example-find-multiple-restaurants-with-ids-3-68} 🌐 Example: Find multiple restaurants with ids 3, 6,8 你可以使用 `$in` 过滤操作符配合一个值数组来查找多个精确值。 🌐 You can use the `$in` filter operator with an array of values to find multiple exact values.
JavaScript 查询(使用 qs 库构建): ## 复杂筛选 {#complex-filtering} 🌐 Complex filtering 复杂过滤是使用高级方法组合多个过滤器,例如结合 `$and` 和 `$or`。这允许更灵活地请求所需的精确数据。 🌐 Complex filtering is combining multiple filters using advanced methods such as combining `$and` & `$or`. This allows for more flexibility to request exactly the data needed.
JavaScript 查询(使用 qs 库构建): ## 深度过滤 {#deep-filtering} 🌐 Deep filtering 深度过滤是对关系的字段进行过滤。 🌐 Deep filtering is filtering on a relation's fields. :::note - 关系、媒体字段、组件和动态区域默认情况下未填充。使用 `populate` 参数来填充这些内容结构(参见 [`populate` 文档`](/cms/api/rest/populate-select#population)) - 你可以过滤填充的内容,也可以过滤嵌套关系,但不能对多态内容结构(例如媒体字段和动态区域)使用过滤器。 ::: :::caution 使用深层过滤器查询你的 API 可能会导致性能问题。如果其中一个深层过滤查询过慢,我们建议构建一个包含优化查询版本的自定义路由。 🌐 Querying your API with deep filters may cause performance issues. If one of your deep filtering queries is too slow, we recommend building a custom route with an optimized version of the query. :::
JavaScript 查询(使用 qs 库构建): # REST API 指南 Source: https://docs.strapi.io/cms/api/rest/guides/intro # REST API 指南 {#rest-api-guides} 🌐 REST API Guides [REST API 参考](/cms/api/rest) 文档旨在为所有可用的端点和参数提供快速参考。 🌐 The [REST API reference](/cms/api/rest) documentation is meant to provide a quick reference for all the endpoints and parameters available. ## 指南 {#guides} 🌐 Guides 以下指南由 Strapi 文档团队官方维护,涵盖专门主题并为某些用例提供详细说明(用 🧠 表示的指南)或分步说明(用 🛠️ 表示的指南): 🌐 The following guides, officially maintained by the Strapi Documentation team, cover dedicated topics and provide detailed explanations (guides indicated with 🧠) or step-by-step instructions (guides indicated with 🛠️) for some use cases: ## 附加资源 {#additional-resources} 🌐 Additional resources :::strapi Want to help other users? 本节中列出的一些附加资源是为 Strapi v4 创建的,可能无法完全适用于 Strapi 5。如果你想将以下文章中的某一篇更新为适用于 Strapi 5,请随时 加入社区写作计划。 ::: 其他教程和指南可以在以下博客文章中找到: 🌐 Additional tutorials and guides can be found in the following blog posts: # 交互式查询构建器 Source: https://docs.strapi.io/cms/api/rest/interactive-query-builder # 使用 Strapi 的交互式工具构建你的查询 URL {#build-your-query-url-with-strapis-interactive-tool} 🌐 Build your query URL with Strapi's interactive tool 可以使用并组合各种参数通过[REST API](/cms/api/rest)查询你的内容,这可能会导致长且复杂的查询URL。 🌐 A wide range of parameters can be used and combined to query your content with the [REST API](/cms/api/rest), which can result in long and complex query URLs. Strapi 的代码库使用 来解析和序列化嵌套的 JavaScript 对象。建议直接使用 `qs` 来生成复杂的查询 URL,而不是手动创建它们。 🌐 Strapi's codebase uses to parse and stringify nested JavaScript objects. It's recommended to use `qs` directly to generate complex query URLs instead of creating them manually. 你可以使用以下交互式查询构建器工具自动生成查询 URL: 🌐 You can use the following interactive query builder tool to generate query URLs automatically: 1. 将 _Endpoint_ 和 _Endpoint Query Parameters_ 字段中的值替换为适合你需求的内容。 2. 点击 **复制到剪贴板** 按钮以复制自动生成的 _查询字符串 URL_,该 URL 会随着你输入而更新。 :::info Parameters usage 请参阅[REST API 参数表](/cms/api/rest/parameters)并阅读相应的参数文档页面,以更好地理解参数的使用。 🌐 Please refer to the [REST API parameters table](/cms/api/rest/parameters) and read the corresponding parameters documentation pages to better understand parameters usage. :::


:::note 默认的端点路径以 `/api/` 为前缀,除非你使用 [ `rest.prefix` API 配置选项](/cms/configurations/api) 配置了不同的 API 前缀,否则应保持不变。
例如,要使用默认 API 前缀查询 `books` 集合类型,请在 _Endpoint_ 字段中输入 `/api/books`。 ::: :::caution Disclaimer 本页面提供的 `qs` 库和交互式查询构建器: 🌐 The `qs` library and the interactive query builder provided on this page: - 可能无法检测到所有语法错误, - 不知道 Strapi 项目中可用的参数和值, - 并且不提供自动补齐功能。 目前,这些工具仅用于将 JavaScript 对象转换为内联查询字符串 URL。使用生成的查询 URL 并不保证你的 API 能返回正确的结果。 🌐 Currently, these tools are only provided to transform the JavaScript object in an inline query string URL. Using the generated query URL does not guarantee that proper results will get returned with your API. ::: # 本地化 Source: https://docs.strapi.io/cms/api/rest/locale # REST API:`locale` {#rest-api-locale} 🌐 REST API: `locale` [国际化 (i18n) 功能](/cms/features/internationalization) 为 [REST API](/cms/api/rest) 添加了新功能。 🌐 The [Internationalization (i18n) feature](/cms/features/internationalization) adds new abilities to the [REST API](/cms/api/rest). :::prerequisites 要使用某个区域设置的 API 内容,请确保该区域设置已在 Strapi 管理面板中 [添加](/cms/features/internationalization#settings)。 🌐 To work with API content for a locale, please ensure the locale has been already [added to Strapi in the admin panel](/cms/features/internationalization#settings). ::: `locale` [API 参数](/cms/api/rest/parameters) 可用于仅处理特定语言环境的文档。`locale` 以语言环境代码作为值(见 ### `GET` 获取特定语言环境中的所有文档 {#rest-get-all} 🌐 `GET` Get all documents in a specific locale ### `GET` 获取特定语言环境的文档 {#rest-get} 🌐 `GET` Get a document in a specific locale 要在指定的区域获取特定文档,请在查询中添加 `locale` 参数: 🌐 To get a specific document in a given locale, add the `locale` parameter to the query: | 使用场景 | 语法格式及更多信息链接 || --- | --- || 在集合类型中 | [`GET /api/content-type-plural-name/document-id?locale=locale-code`](#get-one-collection-type) || 在单一类型中 | [`GET /api/content-type-singular-name?locale=locale-code`](#get-one-single-type) | #### 集合类型 {#get-one-collection-type} 🌐 Collection types 要在给定语言环境中获取集合类型中的特定文档,请在 `documentId` 之后将 `locale` 参数添加到查询中: 🌐 To get a specific document in a collection type in a given locale, add the `locale` parameter to the query, after the `documentId`: #### 单类型 {#get-one-single-type} 🌐 Single types 要在指定区域获取特定单一类型的文档,请在单一类型名称后将 `locale` 参数添加到查询中: 🌐 To get a specific single type document in a given locale, add the `locale` parameter to the query, after the single type name: ### `POST` 为集合类型创建新的本地化文档 {#rest-create} 🌐 `POST` Create a new localized document for a collection type 要从头创建本地化文档,请向内容 API 发送 POST 请求。根据你是要为默认语言创建文档还是为其他语言创建文档,你可能需要在查询中传递 `locale` 参数。 🌐 To create a localized document from scratch, send a POST request to the Content API. Depending on whether you want to create it for the default locale or for another locale, you might need to pass the `locale` parameter in the query. | 使用案例 | 语法格式及更多信息链接 || --- | --- || 为默认语言创建 | [`POST /api/content-type-plural-name`](#rest-create-default-locale) || 为特定语言创建 | [`POST /api/content-type-plural-name?locale=fr`](#rest-create-specific-locale) | #### 对于默认区域设置 {#rest-create-default-locale} 🌐 For the default locale 如果请求主体中未传递任何语言环境,则使用应用的默认语言环境创建文档: 🌐 If no locale has been passed in the request body, the document is created using the default locale for the application: #### 针对特定区域 {#rest-create-specific-locale} 🌐 For a specific locale 要为与默认语言不同的语言环境创建本地化条目,请在 POST 请求的查询 URL 中添加 `locale` 参数: 🌐 To create a localized entry for a locale different from the default one, add the `locale` parameter to the query URL of the POST request: ### `PUT` 为现有文档创建新的本地化版本,或更新现有的本地化版本 {#rest-update} 🌐 `PUT` Create a new, or update an existing, locale version for an existing document 通过向现有文档发送 `PUT` 请求,你可以: 🌐 With `PUT` requests sent to an existing document, you can: - 创建文档的另一个语言环境版本, - 或更新文档的现有语言环境版本。 将 `PUT` 请求发送到相应的 URL,在查询 URL 中添加 `locale=your-locale-code` 参数,并在请求的主体中通过 `data` 对象传递属性: 🌐 Send the `PUT` request to the appropriate URL, adding the `locale=your-locale-code` parameter to the query URL and passing attributes in a `data` object in the request's body: | 用例 | 语法格式及更多信息链接 || --- | --- || 在集合类型中 | [`PUT /api/content-type-plural-name/document-id?locale=locale-code`](#rest-put-collection-type) || 在单一类型中 | [`PUT /api/content-type-singular-name?locale=locale-code`](#rest-put-single-type) | :::caution 为现有本地化条目创建本地化时,请求正文只能接受本地化字段。 🌐 When creating a localization for existing localized entries, the body of the request can only accept localized fields. ::: :::tip Content-Type 应启用 [`createLocalization` 权限](/cms/features/rbac#collection-and-single-types),否则请求将返回 `403: Forbidden` 状态。 🌐 The Content-Type should have the [`createLocalization` permission](/cms/features/rbac#collection-and-single-types) enabled, otherwise the request will return a `403: Forbidden` status. ::: :::note 无法更改现有本地化条目的区域设置。更新本地化条目时,如果在请求正文中设置 `locale` 属性,该属性将被忽略。 🌐 It is not possible to change the locale of an existing localized entry. When updating a localized entry, if you set a `locale` attribute in the request body it will be ignored. ::: #### 在集合类型 {#rest-put-collection-type} 中 🌐 In a collection type 要为集合类型中的现有文档创建新区域,本地化,请在 `documentId` 之后将 `locale` 参数添加到查询中,并将数据传递到请求的主体中: 🌐 To create a new locale for an existing document in a collection type, add the `locale` parameter to the query, after the `documentId`, and pass data to the request's body: #### 在单一类型中 {#rest-put-single-type} 🌐 In a single type 要为现有的单类型文档创建新的本地化版本,请在单类型名称后将 `locale` 参数添加到查询中,并将数据传递到请求的主体中: 🌐 To create a new locale for an existing single type document, add the `locale` parameter to the query, after the single type name, and pass data to the request's body:
### `DELETE` 删除文档的某个语言版本 {#rest-delete} 🌐 `DELETE` Delete a locale version of a document 要删除文档的本地化版本,请发送带有适当 `locale` 参数的 `DELETE` 请求。 🌐 To delete a locale version of a document, send a `DELETE` request with the appropriate `locale` parameter. `DELETE` 请求在成功时仅发送 204 HTTP 状态码,并且不会在响应体中返回任何数据。 #### 在集合类型 {#rest-delete-collection-type} 中 🌐 In a collection type 要仅删除集合类型中文档的特定语言版本,请在 `documentId` 之后将 `locale` 参数添加到查询中: 🌐 To delete only a specific locale version of a document in a collection type, add the `locale` parameter to the query after the `documentId`: #### 在单一类型中 {#rest-delete-single-type} 🌐 In a single type 要仅删除单类型文档的特定语言版本,请在单类型名称后将 `locale` 参数添加到查询中: 🌐 To delete only a specific locale version of a single type document, add the `locale` parameter to the query after the single type name: # 参数 Source: https://docs.strapi.io/cms/api/rest/parameters # REST API 参数 {#rest-api-parameters} 🌐 REST API parameters API 参数可以与 [REST API](/cms/api/rest) 一起使用,以筛选、排序和分页结果,并选择要填充的字段和关联。此外,还可以使用与可选 Strapi 功能相关的特定参数,例如内容类型的发布状态和语言环境。 🌐 API parameters can be used with the [REST API](/cms/api/rest) to filter, sort, and paginate results and to select fields and relations to populate. Additionally, specific parameters related to optional Strapi features can be used, like the publication state and locale of a content-type. 以下 API 参数可用: 🌐 The following API parameters are available: | 运算符 | 类型 | 描述 || --- | --- | --- || `filters` | 对象 | [过滤响应](/cms/api/rest/filters) || `locale` | 字符串 | [选择一个区域设置](/cms/api/rest/locale) || `status` | 字符串 | [选择草稿和发布状态](/cms/api/rest/status) || `populate` | 字符串或对象 | [填充关联、组件或动态区域](/cms/api/rest/populate-select#population) || `fields` | 数组 | [仅选择要显示的特定字段](/cms/api/rest/populate-select#field-selection) || `sort` | 字符串或数组 | [对响应进行排序](/cms/api/rest/sort-pagination.md#sorting) || `pagination` | 对象 | [分页浏览条目](/cms/api/rest/sort-pagination.md#pagination) | :::note 参数中的长括号编码列表(例如 `populate` 或 `fields`)受 [`arrayLimit` 在 `strapi::query`](/cms/configurations/middlewares#query) 的限制。参见 [Population](/cms/api/rest/populate-select#population)。 🌐 Long bracket-encoded lists in a parameter (for example `populate` or `fields`) are limited by [`arrayLimit` on `strapi::query`](/cms/configurations/middlewares#query). See [Population](/cms/api/rest/populate-select#population). ::: 查询参数使用 (即它们使用方括号 `[]` 编码)。 :::tip 可以使用和组合广泛的 REST API 参数来查询你的内容,这可能会导致长且复杂的查询 URL。
👉 你可以使用 Strapi 的[交互式查询构建器](/cms/api/rest/interactive-query-builder)工具更方便地构建查询 URL。🤗 ::: # 填充并选择 Source: https://docs.strapi.io/cms/api/rest/populate-select # REST API:人口和字段选择 {#rest-api-population--field-selection} 🌐 REST API: Population & Field Selection [REST API](/cms/api/rest) 默认不会填充任何关联、媒体字段、组件或动态区域。使用 [`populate` 参数](#population) 来填充特定字段。使用 [`fields` 参数](#field-selection) 仅返回查询结果中的特定字段。 🌐 The [REST API](/cms/api/rest) by default does not populate any relations, media fields, components, or dynamic zones. Use the [`populate` parameter](#population) to populate specific fields. Use the [`fields` parameter](#field-selection) to return only specific fields with the query results. :::tip ## 人口 {#population} 🌐 Population 默认情况下,REST API 不会填充任何类型的字段,因此它不会填充关联、媒体字段、组件或动态区域,除非你传递一个 `populate` 参数来填充各种字段类型。已填充的关联总是返回完整对象;REST API 目前无法仅返回 ID 数组。 🌐 The REST API by default does not populate any type of fields, so it will not populate relations, media fields, components, or dynamic zones unless you pass a `populate` parameter to populate various field types. Populated relations always return full objects; the REST API currently cannot return just an array of IDs. :::prerequisites 必须为正在填充的内容类型启用 `find` 权限。如果某个角色无法访问某个内容类型,则该内容类型将不会被填充(有关如何为内容类型启用 `find` 权限的更多信息,请参见 [用户与权限](/cms/features/users-permissions#editing-a-role))。 🌐 The `find` permission must be enabled for the content-types that are being populated. If a role does not have access to a content-type, the content-type will not be populated (see [Users & Permissions](/cms/features/users-permissions#editing-a-role) for additional information on how to enable `find` permissions for content-types). ::: 你可以单独使用 `populate` 参数,或[与多个操作符结合使用](#combining-population-with-other-operators)以更好地控制人口。 🌐 You can use the `populate` parameter alone or [in combination with multiple operators](#combining-population-with-other-operators) for more control over the population. :::caution `populate=deep` 插件在 Strapi 中 [不推荐使用](https://support.strapi.io/articles/8544110758-why-populate-deep-plugins-are-not-recommended-in-strapi)。 ::: :::note 查询字符串中的大型 `populate` 列表(许多 `populate[0]`、`populate[1]` 等条目)受到查询解析器 `arrayLimit` 的限制(默认值:`100`)。要允许更长的列表,请在 [`strapi::query` 中间件](/cms/configurations/middlewares#query) 上提高 `arrayLimit`。更高的值会增加每个请求的解析开销。 🌐 Large `populate` lists in the query string (many `populate[0]`, `populate[1]`, … entries) are bounded by the query parser `arrayLimit` (default: `100`). To allow a longer list, raise `arrayLimit` on the [`strapi::query` middleware](/cms/configurations/middlewares#query). Higher values increase parsing cost per request. ::: 下表列出了 populate 的用例及示例语法。每一行都链接到“理解 populate”指南以获取详细信息: 🌐 The following table lists populate use cases with example syntax. Each row links to the Understanding populate guide for details: | 用例 | 参数示例语法 | 详细说明阅读 | |-----------| ---|-----------------------| | 填充所有内容,深度 1 级,包括媒体字段、关联、组件和动态区域 | `populate=*` | [填充所有关联和字段,深度 1 级](/cms/api/rest/guides/understanding-populate#populate-all-relations-and-fields-1-level-deep) | | 填充一个关系,
深度为1 | `populate=a-relation-name`| [为特定关系填充1级深度](/cms/api/rest/guides/understanding-populate#populate-1-level-deep-for-specific-relations) | | 填充多个关系,
1 级深 | `populate[0]=relation-name&populate[1]=another-relation-name&populate[2]=yet-another-relation-name`| [为特定关系填充 1 级深](/cms/api/rest/guides/understanding-populate#populate-1-level-deep-for-specific-relations) | | 填充一些关系,几层深 | `populate[root-relation-name][populate][0]=nested-relation-name`| [为特定关系填充几层深](/cms/api/rest/guides/understanding-populate#populate-several-levels-deep-for-specific-relations) | | 填充组件 | `populate[0]=component-name`| [填充组件](/cms/api/rest/guides/understanding-populate#populate-components) | | 填充一个组件及其嵌套组件之一 | `populate[0]=component-name&populate[1]=component-name.nested-component-name`| [填充组件](/cms/api/rest/guides/understanding-populate#populate-components) | | 填充动态区域(仅其第一级元素) | `populate[0]=dynamic-zone-name`| [填充动态区域](/cms/api/rest/guides/understanding-populate#populate-dynamic-zones) | | 使用精确定义的详细填充策略填充动态区域及其嵌套元素和关系 | `populate[dynamic-zone-name][on][component-category.component-name][populate][relation-name][populate][0]=field-name` | [填充动态区域](/cms/api/rest/guides/understanding-populate#populate-dynamic-zones) | :::tip 要构建具有多级填充的复杂查询,请使用 [交互式查询构建器](/cms/api/rest/interactive-query-builder) 工具。有关更详细的说明和示例,请参阅 [REST API 指南](/cms/api/rest/guides/intro)。 🌐 To build complex queries with multiple-level population, use the [interactive query builder](/cms/api/rest/interactive-query-builder) tool. For more detailed explanations and examples, see the [REST API guides](/cms/api/rest/guides/intro). ::: ### 将人口与其他操作符结合 {#combining-population-with-other-operators} 🌐 Combining population with other operators 你可以在填充查询中将 `populate` 操作符与其他操作符结合使用,例如 [字段选择](/cms/api/rest/populate-select#field-selection)、[过滤器](/cms/api/rest/filters) 和 [排序](/cms/api/rest/sort-pagination)。 🌐 You can combine the `populate` operator with other operators such as [field selection](/cms/api/rest/populate-select#field-selection), [filters](/cms/api/rest/filters), and [sort](/cms/api/rest/sort-pagination) in the population queries. :::note 总体和分页运算符不能组合使用。 🌐 The population and pagination operators cannot be combined. ::: #### 用字段选择填充 {#populate-with-field-selection} 🌐 Populate with field selection `fields` 和 `populate` 可以结合。 #### 填充并筛选 {#populate-with-filtering} 🌐 Populate with filtering `filters` 和 `populate` 可以结合。 # 关系 Source: https://docs.strapi.io/cms/api/rest/relations # 管理与 API 请求的关系 {#managing-relations-with-api-requests} 🌐 Managing relations with API requests 定义内容类型(在数据库层中指定为实体)之间的关系是将实体相互连接起来。 🌐 Defining relations between content-types (that are designated as entities in the database layers) is connecting entities with each other. 内容类型之间的关系可以通过[管理面板](/cms/features/content-manager#relational-fields)或通过[REST API](/cms/api/rest)或[文档服务 API](/cms/api/document-service)请求进行管理。 🌐 Relations between content-types can be managed through the [admin panel](/cms/features/content-manager#relational-fields) or through [REST API](/cms/api/rest) or [Document Service API](/cms/api/document-service) requests. 关系可以通过内容 API 连接、断开或设置,只需在请求的主体中传递参数。这些有效负载适用于单条条目关系和多重关系(一对多、多对一、多对多及多向)。当关系字段允许多个链接时,API 需要关系 ID 的数组,并在响应中返回数组。 🌐 Relations can be connected, disconnected or set through the Content API by passing parameters in the body of the request. These payloads work for both single-entry relations and multi relations (one-to-many, many-to-one, many-to-many, and many-way). When a relational field allows multiple links, the API expects arrays of relation IDs and returns arrays in responses. | 参数名称 | 描述 | 更新类型 ||-------------------------|-------------|----------------|| [`connect`](#connect) | 连接新实体。

可以与 `disconnect` 结合使用。

可以与 [位置参数](#relations-reordering) 一起使用,以定义关系的顺序。 | 部分 || [`disconnect`](#disconnect) | 断开实体连接。

可以与 `connect` 结合使用。 | 部分 || [`set`](#set) | 将实体设置为特定集合。使用 `set` 会覆盖与其他实体的所有现有连接。

不能与 `connect` 或 `disconnect` 一起使用。 | 完整 | :::note 多重关系可以通过 REST API 和 [GraphQL API](/cms/api/graphql#fetch-relations) 管理:`connect`、`disconnect` 和 `set` 操作在两个 API 中均可用。然而,[文档服务 API](/cms/api/document-service) 不处理关系。 🌐 Multi relations can be managed from the REST API and the [GraphQL API](/cms/api/graphql#fetch-relations): the `connect`, `disconnect`, and `set` operations are available across both APIs. However, the [Document Service API](/cms/api/document-service) does not handle relations. ::: :::note 当在内容类型上启用[国际化 (i18n)](/cms/features/internationalization)时,你还可以传递一个语言环境以为特定语言环境设置关系,如在此文档服务 API 示例中所示: 🌐 When [Internationalization (i18n)](/cms/features/internationalization) is enabled on the content-type, you can also pass a locale to set relations for a specific locale, as in this Document Service API example: ```js await strapi.documents('api::restaurant.restaurant').update({ documentId: 'a1b2c3d4e5f6g7h8i9j0klm', locale: 'fr', data: { category: { connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv'] } } }) ``` 如果未传递任何语言环境,则将假定使用默认语言环境。 🌐 If no locale is passed, the default locale will be assumed. ::: ## `connect` 在请求体中使用 `connect` 会执行部分更新,连接指定的关系。 🌐 Using `connect` in the body of a request performs a partial update, connecting the specified relations. `connect` 接受简写或长写语法: | 语法类型 | 语法示例 || --- | ---------------- || 简写 | `connect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` || 全写 | ```connect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | 你也可以使用长格式语法来[重新排序关系](#relations-reordering)。 🌐 You can also use the longhand syntax to [reorder relations](#relations-reordering). `connect` 可以与 [`disconnect`](#disconnect) 结合使用。 :::caution `connect` 官方不支持媒体属性。高级用户在技术上可以通过定位上传的文件 ID 来连接媒体条目,但这种方法不被 Strapi 推荐或支持,并且很容易出错(例如,当草稿与发布使用不匹配的 ID 时)。请谨慎操作。 ::: ### 关系重新排序 {#relations-reordering} 🌐 Relations reordering 省略 `position` 参数(如 `documentId: 'srkvrr77k96o44d9v6ef1vu9'`)默认为 `position: { end: true }`。所有其他关系都是相对于另一个已存在的 `id`(使用 `after` 或 `before`)或相对于关系列表(使用 `start` 或 `end`)定位的。操作按 `connect` 数组中定义的顺序依次处理,因此生成的数据库记录将如下所示: 🌐 Omitting the `position` argument (as in `documentId: 'srkvrr77k96o44d9v6ef1vu9'`) defaults to `position: { end: true }`. All other relations are positioned relative to another existing `id` (using `after` or `before`) or relative to the list of relations (using `start` or `end`). Operations are treated sequentially in the order defined in the `connect` array, so the resulting database record will be the following: ```js categories: [ { id: 'nyk7047azdgbtjqhl7btuxw' }, { id: 'j9k8l7m6n5o4p3q2r1s0tuv' }, { id: '6u86wkc6x3parjd4emikhmx6' }, { id: '3r1wkvyjwv0b9b36s7hzpxl7' }, { id: 'a1b2c3d4e5f6g7h8i9j0klm' }, { id: 'rkyqa499i84197l29sbmwzl' }, { id: 'srkvrr77k96o44d9v6ef1vu9' } ] ``` ### 边缘情况:草稿与发布或国际化禁用 {#edge-cases-draft--publish-or-i18n-disabled} 🌐 Edge cases: Draft & Publish or i18n disabled 当 Strapi 5 的某些内置功能在内容类型中被禁用时,例如 [草稿与发布](/cms/features/draft-and-publish) 和 [国际化 (i18n)](/cms/features/internationalization),`connect` 参数可能会有不同的使用方式: 🌐 When some built-in features of Strapi 5 are disabled for a content-type, such as [Draft & Publish](/cms/features/draft-and-publish) and [Internationalization (i18)](/cms/features/internationalization), the `connect` parameter might be used differently: **从 i18n _关闭_ 的 `Category` 到 i18n _开启_ 的 `Article` 的关系:** 在这种情况下,你可以选择要连接到哪个语言环境: 🌐 In this situation you can select which locale you are connecting to: ```js data: { categories: { connect: [ { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'en' }, // Connect to the same document id but with a different locale 👇 { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', locale: 'fr' }, ] } } ``` **从 Draft & Publish _关闭_ 的 `Category` 到 Draft & Publish _开启_ 的 `Article` 的关系:** ```js data: { categories: { connect: [ { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'draft' }, // Connect to the same document id but with different publication states 👇 { documentId: 'z0y2x4w6v8u1t3s5r7q9onm', status: 'published' }, ] } } ``` ## `disconnect` 在请求的主体中使用 `disconnect` 会执行部分更新,断开指定的关联。 🌐 Using `disconnect` in the body of a request performs a partial update, disconnecting the specified relations. `disconnect` 接受简写或长写语法: | 语法类型 | 语法示例 || ---|----------------|| 简写 | `disconnect: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` || 全写 | ```disconnect: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | `disconnect` 可以与 [`connect`](#connect) 结合使用。
## `set` 使用 `set` 会执行完整更新,用指定的顺序用指定的关系替换所有现有关系。 🌐 Using `set` performs a full update, replacing all existing relations with the ones specified, in the order specified. `set` 接受简写或长写语法: | 语法类型 | 语法示例 || --- | --- || 简写 | `set: ['z0y2x4w6v8u1t3s5r7q9onm', 'j9k8l7m6n5o4p3q2r1s0tuv']` || 全写 | ```set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }]``` | 由于 `set` 会替换所有现有关系,因此不应与其他参数一起使用。要执行部分更新,请使用 [`connect`](#connect) 和 [`disconnect`](#disconnect)。 🌐 As `set` replaces all existing relations, it should not be used in combination with other parameters. To perform a partial update, use [`connect`](#connect) and [`disconnect`](#disconnect). :::note Omitting set 省略任何参数等同于使用 `set`。
例如,以下三种语法都是等效的: - `data: { categories: set: [{ documentId: 'z0y2x4w6v8u1t3s5r7q9onm' }, { documentId: 'j9k8l7m6n5o4p3q2r1s0tuv' }] }}` - `data: { categories: set: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }}` - `data: { categories: ['z0y2x4w6v8u1t3s5r7q9onm2', 'j9k8l7m6n5o4p3q2r1s0tuv'] }` ::: # 排序与分页 Source: https://docs.strapi.io/cms/api/rest/sort-pagination # REST API:排序与分页 {#rest-api-sort--pagination} 🌐 REST API: Sort & Pagination 通过对 [REST API](/cms/api/rest) 的查询返回的条目可以进行排序和分页。 🌐 Entries that are returned by queries to the [REST API](/cms/api/rest) can be sorted and paginated. :::tip
JavaScript 查询(使用 qs 库构建): ### 示例:使用两个字段排序并设置顺序 {#example-sort-using-2-fields-and-set-the-order} 🌐 Example: Sort using 2 fields and set the order 使用 `sort` 参数并在已排序的字段上定义 `:asc` 或 `:desc`,你可以获得按特定顺序排序的结果。 🌐 Using the `sort` parameter and defining `:asc` or `:desc` on sorted fields, you can get results sorted in a particular order.
JavaScript 查询(使用 qs 库构建): ## 分页 {#pagination} 🌐 Pagination 查询可以接受 `pagination` 参数。结果可以分页: 🌐 Queries can accept `pagination` parameters. Results can be paginated: - 可以通过 [page](#pagination-by-page)(即,指定页码和每页条目数) - 或者通过 [offset](#pagination-by-offset)(即指定要跳过多少条条目以及要返回多少条) :::note 分页方法不能混合使用。始终要么使用 `page` 和 `pageSize`,**或者**使用 `start` 和 `limit`。 🌐 Pagination methods can not be mixed. Always use either `page` with `pageSize` **or** `start` with `limit`. ::: ### 按页分页 {#pagination-by-page} 🌐 Pagination by page 要按页对结果进行分页,请使用以下参数: 🌐 To paginate results by page, use the following parameters: | 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || `pagination[page]` | 整数 | 页码 | 1 || `pagination[pageSize]` | 整数 | 每页数量 | 25 || `pagination[withCount]` | 布尔值 | 在响应中添加条目总数和页数 | True |
JavaScript 查询(使用 qs 库构建): ### 按偏移量分页 {#pagination-by-offset} 🌐 Pagination by offset 要按偏移量对结果进行分页,请使用以下参数: 🌐 To paginate results by offset, use the following parameters: | 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || `pagination[start]` | 整数 | 起始值(即要返回的第一个条目) | 0 || `pagination[limit]` | 整数 | 要返回的条目数量 | 25 || `pagination[withCount]` | 布尔值 | 切换是否在响应中显示条目总数 | `true` | :::tip `pagination[limit]` 的默认值和最大值可以在 `/cms/configurations/api` 文件中的 `./config/api.js` 配置里通过 `api.rest.defaultLimit` 和 `api.rest.maxLimit` 键进行设置。 🌐 The default and maximum values for `pagination[limit]` can be [configured in the `./config/api.js`](/cms/configurations/api) file with the `api.rest.defaultLimit` and `api.rest.maxLimit` keys. :::
JavaScript 查询(使用 qs 库构建): # 状态 Source: https://docs.strapi.io/cms/api/rest/status # REST API:`status` {#rest-api-status} 🌐 REST API: `status` [REST API](/cms/api/rest) 提供根据状态(草稿或已发布)过滤结果的功能。 🌐 The [REST API](/cms/api/rest) offers the ability to filter results based on their status, draft or published. :::prerequisites 应该启用 [Draft & Publish](/cms/features/draft-and-publish) 功能。 🌐 The [Draft & Publish](/cms/features/draft-and-publish) feature should be enabled. ::: 查询可以接受一个 `status` 参数以根据其状态获取文档: 🌐 Queries can accept a `status` parameter to fetch documents based on their status: - `published`:仅返回文档的已发布版本(默认) - `draft`:仅返回文档的草稿版本 :::tip 在响应数据中,`publishedAt` 字段对于草稿来说是 `null`。 🌐 In the response data, the `publishedAt` field is `null` for drafts. ::: :::note 由于默认返回已发布版本,因此不传递状态参数等同于传递 `status=published`。 🌐 Since published versions are returned by default, passing no status parameter is equivalent to passing `status=published`. :::

JavaScript 查询(使用 qs 库构建): # 上传文件 Source: https://docs.strapi.io/cms/api/rest/upload # REST API:上传文件 {#rest-api-upload-files} 🌐 REST API: Upload files [媒体库功能](/cms/features/media-library) 在 Strapi 的后端服务器中由 `upload` 包提供支持。要向 Strapi 上传文件,你可以直接从管理面板使用媒体库,也可以使用 [REST API](/cms/api/rest),可用的端点如下: 🌐 The [Media Library feature](/cms/features/media-library) is powered in the back-end server of Strapi by the `upload` package. To upload files to Strapi, you can either use the Media Library directly from the admin panel, or use the [REST API](/cms/api/rest), with the following available endpoints : | 方法 | 路径 | 描述 || :----- | :---------------------- | :------------------ || GET | `/api/upload/files` | 获取文件列表 || GET | `/api/upload/files/:id` | 获取特定文件 || POST | `/api/upload` | 上传文件 || POST | `/api/upload?id=x` | 更新文件信息 || DELETE | `/api/upload/files/:id` | 删除文件 | :::note Notes - [文件夹](/cms/features/media-library#organizing-assets-with-folders) 是仅限管理员面板的功能,不属于内容 API(REST 或 GraphQL)。通过 REST 上传的文件位于自动创建的“API 上传”文件夹中。 - GraphQL API 不支持上传媒体文件。要上传文件,请使用 REST API 或直接从管理面板的 [媒体库](/cms/features/media-library) 添加文件。一些用于更新或删除已上传媒体文件的 GraphQL 变更仍然可能(详情请参见 [GraphQL API 文档](/cms/api/graphql#mutations-on-media-files))。 ::: ## 上传文件 {#upload-files} 🌐 Upload files 将一个或多个文件上传到你的应用。 🌐 Upload one or more files to your application. `files` 是唯一接受的参数,用于描述要上传的文件。其值可以是 Buffer 或 Stream。 :::tip 上传图片时,包含一个 `fileInfo` 对象以设置文件名、替代文本和标题。 🌐 When uploading an image, include a `fileInfo` object to set the file name, alt text, and caption. ::: :::caution 你必须在请求正文中发送 FormData。 🌐 You have to send FormData in your request body. ::: ## 上传入口文件 {#upload-entry-files} 🌐 Upload entry files 上传一个或多个将链接到特定条目的文件。 🌐 Upload one or more files that will be linked to a specific entry. 接受以下参数: 🌐 The following parameters are accepted: | 参数 | 描述 || --- | --- ||`files` | 要上传的文件。值可以是 Buffer 或 Stream。 ||`path` (可选) | 文件将上传到的文件夹(仅在 strapi-provider-upload-aws-s3 上支持)。 || `refId` | 将与文件关联的条目 ID。 || `ref` | 文件将关联的模型的唯一 ID(uid)(详见下文)。 || `source` (可选) | 模型所在插件的名称。 || `field` | 文件将精确关联到的条目字段。 | 例如,给定 `Restaurant` 模型属性: 🌐 For example, given the `Restaurant` model attributes: ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... "attributes": { "name": { "type": "string" }, "cover": { "type": "media", "multiple": false, } } // ... } ``` 以下是相应前端的示例代码: 🌐 The following is an example of a corresponding front-end code: ```html
``` :::caution 你必须在请求正文中发送 FormData。 🌐 You have to send FormData in your request body. ::: ## 更新文件信息 {#update-fileinfo} 🌐 Update fileInfo 更新应用中的文件。 🌐 Update a file in your application. `fileInfo` 是唯一被接受的参数,用于描述要更新的文件信息: ```js const fileId = 50; const newFileData = { alternativeText: 'My new alternative text for this image!', }; const form = new FormData(); form.append('fileInfo', JSON.stringify(newFileData)); const response = await fetch(`http://localhost:1337/api/upload?id=${fileId}`, { method: 'post', body: form, }); ``` ## 模型定义 {#models-definition} 🌐 Models definition 向[模型](/cms/backend-customization/models)(或另一个插件的模型)添加文件属性就像添加一个新的关联。 🌐 Adding a file attribute to a [model](/cms/backend-customization/models) (or the model of another plugin) is like adding a new association. 以下示例允许你上传并附加一个文件到 `avatar` 属性: 🌐 The following example lets you upload and attach one file to the `avatar` attribute: ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... { "attributes": { "pseudo": { "type": "string", "required": true }, "email": { "type": "email", "required": true, "unique": true }, "avatar": { "type": "media", "multiple": false, } } } // ... } ``` 以下示例允许你上传并附加多张图片到 `restaurant` 内容类型: 🌐 The following example lets you upload and attach multiple pictures to the `restaurant` content-type: ```json title="/src/api/restaurant/content-types/restaurant/schema.json" { // ... { "attributes": { "name": { "type": "string", "required": true }, "covers": { "type": "media", "multiple": true, } } } // ... } ``` # 后端定制 Source: https://docs.strapi.io/cms/backend-customization
# 后端自定义 :::strapi Disambiguation: Strapi back end 作为一个无头 CMS,Strapi 软件整体上可以被视为你网站或应用的“后端”。 但 Strapi 软件本身包含两个不同的部分: 🌐 As a headless CMS, the Strapi software as a whole can be considered as the "back end" of your website or application. But the Strapi software itself includes 2 different parts: - Strapi 的 **后端** 部分是 Strapi 运行的一个 HTTP 服务器。像任何 HTTP 服务器一样,Strapi 后端接收请求并发送响应。你的内容存储在数据库中,Strapi 后端与数据库交互以创建、检索、更新和删除内容。 - Strapi 的 **前端** 部分称为管理面板。管理面板提供图形用户界面,帮助你组织和管理内容。 在整个开发者文档中,“后端”专指 Strapi 的后端部分。 🌐 Throughout this developer documentation, 'back end' refers _exclusively_ to the back-end part of Strapi. [入门 > 管理员面板页面](/cms/features/admin-panel) 提供了管理员面板的概览,[管理员面板自定义部分](/cms/admin-panel-customization) 详细说明了管理员面板可用的各种自定义选项。 🌐 The [Getting Started > Admin panel page](/cms/features/admin-panel) gives an admin panel overview and the [admin panel customization section](/cms/admin-panel-customization) details the various customization options available for the admin panel. ::: Strapi 后端运行一个基于 的 HTTP 服务器, 是一个后端 JavaScript 框架。 像任何 HTTP 服务器一样,Strapi 后端接收请求并发送响应。你可以通过 [REST](/cms/api/rest) 或 [GraphQL](/cms/api/graphql) API 向 Strapi 后端发送请求,以创建、检索、更新或删除数据。 🌐 Like any HTTP server, the Strapi back end receives requests and send responses. You can send requests to the Strapi back end to create, retrieve, update, or delete data through the [REST](/cms/api/rest) or [GraphQL](/cms/api/graphql) APIs. 请求可以通过 Strapi 后端传输,如下所示: 🌐 A request can travel through the Strapi back end as follows: 1. Strapi 服务器接收一个 [请求](/cms/backend-customization/requests-responses)。 2. 请求会触发按顺序运行的[全局中间件](/cms/backend-customization/middlewares)。 3. 该请求访问了一个[路由](/cms/backend-customization/routes)。
默认情况下,Strapi 会为你创建的所有内容类型生成路由文件(参见[REST API 文档](/cms/api/rest)),并且可以添加和配置更多路由。 4. [路由策略](/cms/backend-customization/policies) 充当只读的验证步骤,可以阻止访问某条路由。[路由中间件](/cms/backend-customization/routes#middlewares) 可以控制请求流程,并在继续之前修改请求本身。 5. [控制器](/cms/backend-customization/controllers) 在路由被访问后执行代码。[服务](/cms/backend-customization/services) 是可选的附加代码,可用于构建可被控制器重复使用的自定义逻辑。 6. 控制器和服务执行的代码与[模型](/cms/backend-customization/models)交互,这些模型是存储在数据库中的内容结构的表示形式。
通过模型表示的数据的交互由[文档服务](/cms/api/document-service)和[查询引擎](/cms/api/query-engine)处理。 7. 你可以实现 [文档服务中间件](/cms/api/document-service/middlewares) 来在数据发送到查询引擎之前进行控制。查询引擎也可以使用生命周期钩子,不过我们建议你使用文档服务中间件,除非你确实需要直接与数据库交互。 7. 服务器返回一个 [响应](/cms/backend-customization/requests-responses)。响应可以在发送之前通过路由中间件和全局中间件返回。 全局和路由中间件都包含一个异步回调函数 `await next()`。根据中间件返回的内容,请求将在后端走一条较短或较长的路径: 🌐 Both global and route middlewares include an asynchronous callback function, `await next()`. Depending on what is returned by the middleware, the request will either go through a shorter or longer path through the back end: * 如果中间件不返回任何内容,则请求将继续穿过后端的各个核心元素(即控制器、服务以及与数据库交互的其他层)。 * 如果中间件在调用 `await next()` 之前返回,将会立即发送响应,跳过其余的核心元素。然后,它将沿着原路返回同一条链。 :::info 请注意,本节页面中描述的所有自定义仅适用于 REST API。[GraphQL 自定义](/cms/plugins/graphql#customization) 在 GraphQL 插件文档中描述。 🌐 Please note that all customizations described in the pages of this section are only for the REST API. [GraphQL customizations](/cms/plugins/graphql#customization) are described in the GraphQL plugin documentation. ::: ## 交互式图表 {#interactive-diagram} 🌐 Interactive diagram 下图展示了请求如何通过 Strapi 后端传输。你可以点击任意形状跳转到文档中的相关页面。 🌐 The following diagram represents how requests travel through the Strapi back end. You can click on any shape to jump to the relevant page in the documentation.
# 控制器 Source: https://docs.strapi.io/cms/backend-customization/controllers # 控制器 {#controllers} 🌐 Controllers 控制器是包含一组方法(称为动作)的 JavaScript 文件,客户端可以根据请求的[路由](/cms/backend-customization/routes)访问这些方法。每当客户端请求该路由时,动作会执行业务逻辑代码并返回[响应](/cms/backend-customization/requests-responses)。控制器代表模型-视图-控制器(MVC)模式中的 C。 🌐 Controllers are JavaScript files that contain a set of methods, called actions, reached by the client according to the requested [route](/cms/backend-customization/routes). Whenever a client requests the route, the action performs the business logic code and sends back the [response](/cms/backend-customization/requests-responses). Controllers represent the C in the model-view-controller (MVC) pattern. 在大多数情况下,控制器将包含项目大部分的业务逻辑。但随着控制器的逻辑变得越来越复杂,使用[服务](/cms/backend-customization/services)将代码组织成可重用的部分是一种好习惯。 🌐 In most cases, the controllers will contain the bulk of a project's business logic. But as a controller's logic becomes more and more complicated, it's a good practice to use [services](/cms/backend-customization/services) to organize the code into re-usable parts.
Simplified Strapi backend diagram with controllers highlighted
该图表示请求在 Strapi 后端传递的简化版本,控制器被高亮。后端自定义介绍页面包含一个完整的, 交互式图表
:::caution Sanitize inputs and outputs 在重写核心操作时,始终验证和清理查询和响应,以避免泄露私有字段或绕过访问规则。在从自定义操作返回数据之前,使用 `validateQuery`(可选)、`sanitizeQuery`(推荐)和 `sanitizeOutput`。请参见下面的示例,了解安全的 `find` 重写。 🌐 When overriding core actions, always validate and sanitize queries and responses to avoid leaking private fields or bypassing access rules. Use `validateQuery` (optional), `sanitizeQuery` (recommended), and `sanitizeOutput` before returning data from custom actions. See the example below for a safe `find` override. ::: ## 实现 {#implementation} 🌐 Implementation 控制器可以[生成或手动添加](#adding-a-new-controller)。Strapi 提供了一个 `createCoreController` 工厂函数,可以自动生成核心控制器,并允许构建自定义控制器或[扩展或替换生成的控制器](#extending-core-controllers)。 🌐 Controllers can be [generated or added manually](#adding-a-new-controller). Strapi provides a `createCoreController` factory function that automatically generates core controllers and allows building custom ones or [extend or replace the generated controllers](#extending-core-controllers). ### 添加新控制器 {#adding-a-new-controller} 🌐 Adding a new controller 可以实现一个新的控制器: 🌐 A new controller can be implemented: - 使用 [交互式 CLI 命令 `strapi generate`](/cms/cli) - 或通过创建 JavaScript 文件手动: - 在 `./src/api/[api-name]/controllers/` 中用于 API 控制器(此位置很重要,因为 Strapi 会从这里自动加载控制器) - 或者在像 `./src/plugins/[plugin-name]/server/controllers/` 这样的文件夹中用于插件控制器,尽管它们可以创建在其他地方,只要插件接口在 `strapi-server.js` 文件中正确导出(参见 [插件的服务器 API 文档](/cms/plugins-development/server-api)) 每个控制器动作可以是 `async` 或 `sync` 函数。每个动作都接收一个上下文对象(`ctx`)作为参数。`ctx` 包含 [请求上下文](/cms/backend-customization/requests-responses#ctxrequest) 和 [响应上下文](/cms/backend-customization/requests-responses#ctxresponse)。 🌐 Each controller action can be an `async` or `sync` function. Every action receives a context object (`ctx`) as a parameter. `ctx` contains the [request context](/cms/backend-customization/requests-responses#ctxrequest) and the [response context](/cms/backend-customization/requests-responses#ctxresponse).
示例:GET /hello 路由调用一个基本控制器 定义了一个特定的 `GET /hello` [路由](/cms/backend-customization/routes),路由文件的名称(即 `index`)用于调用控制器处理程序(即 `index`)。每次向服务器发送 `GET /hello` 请求时,Strapi 会在 `hello.js` 控制器中调用 `index` 操作,并返回 `Hello World!`: 🌐 A specific `GET /hello` [route](/cms/backend-customization/routes) is defined, the name of the router file (i.e. `index`) is used to call the controller handler (i.e. `index`). Every time a `GET /hello` request is sent to the server, Strapi calls the `index` action in the `hello.js` controller, which returns `Hello World!`:
:::note 当创建一个新的 [内容类型](/cms/backend-customization/models#content-types) 时,Strapi 会生成一个带有占位代码的通用控制器,准备进行自定义。 🌐 When a new [content-type](/cms/backend-customization/models#content-types) is created, Strapi builds a generic controller with placeholder code, ready to be customized. ::: :::tip 要了解自定义控制器可能的高级用法,请阅读后端自定义示例手册的 [服务和控制器](/cms/backend-customization/examples/services-and-controllers) 页面。 🌐 To see a possible advanced usage for custom controllers, read the [services and controllers](/cms/backend-customization/examples/services-and-controllers) page of the backend customization examples cookbook. ::: ### 控制器与路由:路由如何到达控制器动作 {#controllers--routes-how-routes-reach-controller-actions} 🌐 Controllers & Routes: How routes reach controller actions - 核心映射是自动补齐的:当你生成一个内容类型时,Strapi 会创建匹配的控制器和一个已经针对标准操作(`find`、`findOne`、`create`、`update` 和 `delete`)的路由文件。在生成的控制器中覆盖这些操作中的任何一个不需要修改路由——路由保持相同的处理程序字符串并执行你更新后的逻辑。 - 添加路由应仅针对新的操作或路径进行。如果引入一个全新的方法,例如 `exampleAction`,则创建或更新一个路由条目,其 `handler` 指向该操作,以便 HTTP 请求可以访问它。使用完整限定的处理程序语法 `::..`(例如 API 控制器的 `api::restaurant.restaurant.exampleAction` 或插件控制器的 `plugin::menus.menu.exampleAction`)。 - 关于控制器和路由文件名:默认的控制器名称来自 `./src/api/[api-name]/controllers/` 中的文件名。使用 `createCoreRouter` 创建的核心路由采用相同的名称,因此生成的处理程序字符串会自动匹配。自定义路由可以遵循任何文件命名方案,只要 `handler` 字符串引用一个导出的控制器操作。 以下示例添加了一个新的控制器操作,并通过自定义路由将其公开,而不会重复现有的 CRUD 路由定义: 🌐 The example below adds a new controller action and exposes it through a custom route without duplicating the existing CRUD route definitions: ```js title="./src/api/restaurant/controllers/restaurant.js" const { createCoreController } = require('@strapi/strapi').factories; module.exports = createCoreController('api::restaurant.restaurant', ({ strapi }) => ({ async exampleAction(ctx) { const specials = await strapi.service('api::restaurant.restaurant').find({ filters: { isSpecial: true } }); return this.transformResponse(specials.results); }, })); ``` ```js title="./src/api/restaurant/routes/01-custom-restaurant.js" module.exports = { routes: [ { method: 'GET', path: '/restaurants/specials', handler: 'api::restaurant.restaurant.exampleAction', }, ], }; ``` ### 控制器中的清理和验证 {#sanitization-and-validation-in-controllers} 🌐 Sanitization and Validation in controllers :::warning 强烈建议你使用新的 `sanitizeQuery` 和 `validateQuery` 函数对传入的请求查询进行消毒(v4.8.0+)和/或验证(v4.13.0+),以防止私有数据泄露。 🌐 It's strongly recommended you sanitize (v4.8.0+) and/or validate (v4.13.0+) your incoming request query utilizing the new `sanitizeQuery` and `validateQuery` functions to prevent the leaking of private data. ::: 清理意味着对象被“清理”并返回。 🌐 Sanitization means that the object is “cleaned” and returned. 验证意味着断言数据已经干净,如果发现不应该存在的内容,则会引发错误。 🌐 Validation means an assertion is made that the data is already clean and throws an error if something is found that shouldn't be there. 在 Strapi 5 中,查询参数和输入数据(即创建和更新的请求体数据)都会被验证。任何包含以下无效输入的创建和更新数据请求都会抛出 `400 Bad Request` 错误: 🌐 In Strapi 5, both query parameters and input data (i.e., create and update body data) are validated. Any create and update data requests with the following invalid input will throw a `400 Bad Request` error: - 用户无权创建的关系 - 模式中不存在的无法识别的值 - 不可写字段和内部时间戳,如 `createdAt` 和 `createdBy` 字段 - 设置或更新 `id` 字段(连接关系除外) #### 使用控制器工厂时的消毒 {#sanitization-when-utilizing-controller-factories} 🌐 Sanitization when utilizing controller factories 在 Strapi 工厂中,公开了以下可用于清理和验证的函数: 🌐 Within the Strapi factories the following functions are exposed that can be used for sanitization and validation: | 函数名称 | 参数 | 描述 ||------------------|----------------------------|--------------------------------------------------------------------------------------|| `sanitizeQuery` | `ctx` | 清理请求查询 || `sanitizeOutput` | `entity`/`entities`, `ctx` | 清理输出数据,其中实体/实体集合应为对象或数据数组 || `sanitizeInput` | `data`, `ctx` | 清理输入数据 || `validateQuery` | `ctx` | 验证请求查询(在参数无效时抛出错误) || `validateInput` | `data`, `ctx` | (实验性)验证输入数据(在数据无效时抛出错误) | 这些函数自动从模型继承清理设置,并根据内容类型架构和任何内容 API 身份验证策略(例如用户和权限插件或 API 令牌)相应地清理数据。 🌐 These functions automatically inherit the sanitization settings from the model and sanitize the data accordingly based on the content-type schema and any of the content API authentication strategies, such as the Users & Permissions plugin or API tokens. :::warning 因为这些方法使用的是与当前控制器关联的模型,如果你查询的数据来自另一个模型(例如,在“restaurant”控制器方法中查找“menus”),你必须改为使用 `strapi.contentAPI` 方法,例如在 [Sanitizing Custom Controllers](#sanitize-validate-custom-controllers) 中描述的 `strapi.contentAPI.sanitize.query`,否则你的查询结果将会被错误的模型进行清理。 🌐 Because these methods use the model associated with the current controller, if you query data that is from another model (i.e., doing a find for "menus" within a "restaurant" controller method), you must instead use the `strapi.contentAPI` methods, such as `strapi.contentAPI.sanitize.query` described in [Sanitizing Custom Controllers](#sanitize-validate-custom-controllers), or else the result of your query will be sanitized against the wrong model. ::: #### 构建自定义控制器时的清理和验证 {#sanitize-validate-custom-controllers} 🌐 Sanitization and validation when building custom controllers 在自定义控制器中,Strapi 通过 `strapi.contentAPI` 提供以下用于清理和验证的函数。要向内容 API 路由(例如在 `register` 中)添加自定义查询或请求体参数,请参见 [自定义内容 API 参数](/cms/backend-customization/routes#custom-content-api-parameters)。 🌐 Within custom controllers, Strapi exposes the following functions via `strapi.contentAPI` for sanitization and validation. To add custom query or body parameters to Content API routes (e.g. in `register`), see [Custom Content API parameters](/cms/backend-customization/routes#custom-content-api-parameters). | 函数名 | 参数 | 描述 | |------------------------------|--------------------|---------------------------------------------------------| | `strapi.contentAPI.sanitize.input` | `data`,`schema`,`auth` | 清理请求输入,包括不可写字段,移除受限制的关系,以及其他由插件添加的嵌套“访问者” | | `strapi.contentAPI.sanitize.output` | `data`、`schema`、`auth` | 清理响应输出,包括受限制的关系、私有字段、密码以及插件添加的其他嵌套“访问者” | | `strapi.contentAPI.sanitize.query` | `ctx.query`、`schema`、`auth` | 清理请求查询,包括过滤器、排序、字段和填充 | | `strapi.contentAPI.validate.query` | `ctx.query`、`schema`、`auth` | 验证请求查询,包括过滤器、排序、字段(当前未填充) | | `strapi.contentAPI.validate.input` | `data`、`schema`、`auth` |(实验性)验证请求输入,包括不可写字段、移除受限关系,以及插件添加的其他嵌套“访问器”| :::note 根据自定义控制器的复杂性,你可能需要 Strapi 目前无法考虑的额外清理,尤其是在组合多个来源的数据时。 🌐 Depending on the complexity of your custom controllers, you may need additional sanitization that Strapi cannot currently account for, especially when combining the data from multiple sources. ::: ### 扩展核心控制器 {#extending-core-controllers} 🌐 Extending core controllers 每种内容类型都会创建默认的控制器和操作。这些默认控制器用于响应 API 请求(例如,当访问 `GET /api/articles/3` 时,会调用 “Article” 内容类型默认控制器的 `findOne` 操作)。默认控制器可以自定义以实现你自己的逻辑。以下代码示例应能帮助你入门。 🌐 Default controllers and actions are created for each content-type. These default controllers are used to return responses to API requests (e.g. when `GET /api/articles/3` is accessed, the `findOne` action of the default controller for the "Article" content-type is called). Default controllers can be customized to implement your own logic. The following code examples should help you get started. :::tip 核心控制器的一个操作可以完全通过[创建自定义操作](#adding-a-new-controller)来替换,并将该操作命名为与原操作相同的名称(例如 `find`、`findOne`、`create`、`update` 或 `delete`)。 🌐 An action from a core controller can be replaced entirely by [creating a custom action](#adding-a-new-controller) and naming the action the same as the original action (e.g. `find`, `findOne`, `create`, `update`, or `delete`). ::: :::tip 在扩展核心控制器时,你无需重新实现任何清理功能,因为这些功能已经由你扩展的核心控制器处理。尽可能强烈建议扩展核心控制器,而不是创建自定义控制器。 🌐 When extending a core controller, you do not need to re-implement any sanitization as it will already be handled by the core controller you are extending. Where possible it's strongly recommended to extend the core controller instead of creating a custom controller. :::
集合类型示例 :::tip [后端自定义示例手册](/cms/backend-customization/examples)展示了如何覆盖默认的控制器操作,例如针对[`create`操作](/cms/backend-customization/examples/services-and-controllers#custom-controller)。 🌐 The [backend customization examples cookbook](/cms/backend-customization/examples) shows how you can overwrite a default controller action, for instance for the [`create` action](/cms/backend-customization/examples/services-and-controllers#custom-controller). :::
单类型示例
## 使用 {#usage} 🌐 Usage 控制器被声明并附加到一个路由上。当路由被调用时,控制器会自动被调用,因此通常不需要显式调用控制器。但是,[服务](/cms/backend-customization/services) 可以调用控制器,在这种情况下应使用以下语法: 🌐 Controllers are declared and attached to a route. Controllers are automatically called when the route is called, so controllers usually do not need to be called explicitly. However, [services](/cms/backend-customization/services) can call controllers, and in this case the following syntax should be used: ```js // access an API controller strapi.controller('api::api-name.controller-name'); // access a plugin controller strapi.controller('plugin::plugin-name.controller-name'); ``` :::tip 要列出所有可用的控制器,请运行 `yarn strapi controllers:list`。 🌐 To list all the available controllers, run `yarn strapi controllers:list`. ::: # 中间件 Source: https://docs.strapi.io/cms/backend-customization/middlewares # 中间件定制 {#middlewares-customization} 🌐 Middlewares customization 全局作用域的自定义中间件应该添加到 [中间件配置文件](/cms/configurations/middlewares#loading-order),否则 Strapi 将无法加载它们。 🌐 Globally scoped custom middlewares should be added to the [middlewares configuration file](/cms/configurations/middlewares#loading-order) or Strapi won't load them. API 级别和插件中间件可以添加到与其相关的特定路由中,如下所示: 🌐 API level and plugin middlewares can be added into the specific router that they are relevant to like the following: ```js title="./src/api/[api-name]/routes/[collection-name].js or ./src/plugins/[plugin-name]/server/routes/index.js" module.exports = { routes: [ { method: "GET", path: "/[collection-name]", handler: "[controller].find", config: { middlewares: ["[middleware-name]"], // See the usage section below for middleware naming conventions }, }, ], }; ```
自定义计时器中间件示例
GraphQL 插件还允许[实现自定义中间件](/cms/plugins/graphql#middlewares),语法有所不同。 🌐 The GraphQL plugin also allows [implementing custom middlewares](/cms/plugins/graphql#middlewares), with a different syntax. :::tip Discover loaded middlewares 运行 `yarn strapi middlewares:list` 列出所有已注册的中间件,并在将它们连接到路由时仔细检查名称。 🌐 Run `yarn strapi middlewares:list` to list all registered middlewares and double‑check naming when wiring them in routers. ::: ## 使用 {#usage} 🌐 Usage 中间件根据其范围有不同的调用方式: 🌐 Middlewares are called different ways depending on their scope: - 在应用级中间件中使用 `global::middleware-name` - 使用 `api::api-name.middleware-name` 进行 API 级中间件 - 使用 `plugin::plugin-name.middleware-name` 作为插件中间件 :::tip 要列出所有已注册的中间件,运行 `yarn strapi middlewares:list`。 🌐 To list all the registered middlewares, run `yarn strapi middlewares:list`. ::: ### 使用“是所有者策略”限制内容访问 {#restricting-content-access-with-an-is-owner-policy} 🌐 Restricting content access with an "is-owner policy" 通常要求条目的作者是唯一被允许编辑或删除该条目的用户。在 Strapi 的早期版本中,这被称为“is-owner 策略”。在 Strapi v4 中,实现此行为的推荐方式是使用中间件。 🌐 It is often required that the author of an entry is the only user allowed to edit or delete the entry. In previous versions of Strapi, this was known as an "is-owner policy". With Strapi v4, the recommended way to achieve this behavior is to use a middleware. 正确的实现很大程度上取决于你的项目的需求和自定义代码,但最基本的实现可以通过以下过程来实现: 🌐 Proper implementation largely depends on your project's needs and custom code, but the most basic implementation could be achieved with the following procedure: 1. 在你的项目文件夹中,通过在终端运行 `yarn strapi generate`(或 `npm run strapi generate`)命令,使用 Strapi CLI 生成器创建一个中间件。 2. 使用键盘箭头从列表中选择 `middleware`,然后按回车键。 3. 给中间件起一个名字,例如 `isOwner`。 4. 从列表中选择 `Add middleware to an existing API`。 5. 选择你希望中间件应用哪个 API。 6. 将 `/src/api/[your-api-name]/middlewares/isOwner.js` 文件中的代码替换为以下内容,并在第 22 行将 `api::restaurant.restaurant` 替换为你在第 5 步选择的 API 对应的标识符(例如,如果你的 API 名称是 `blog-post`,则替换为 `api::blog-post.blog-post`): ```js showLineNumbers title="src/api/blog-post/middlewares/isOwner.js" "use strict"; /** * `isOwner` middleware */ module.exports = (config, { strapi }) => { // Add your own logic here. return async (ctx, next) => { const user = ctx.state.user; const entryId = ctx.params.id ? ctx.params.id : undefined; let entry = {}; /** * Gets all information about a given entry, * populating every relations to ensure * the response includes author-related information */ if (entryId) { entry = await strapi.documents('api::restaurant.restaurant').findOne( entryId, { populate: "*" } ); } /** * Compares user id and entry author id * to decide whether the request can be fulfilled * by going forward in the Strapi backend server */ if (user.id !== entry.author.id) { return ctx.unauthorized("This action is unauthorized."); } else { return next(); } }; }; ``` 7. 确保中间件配置应用于某些路由。在 `src/api/[your-api–name]/routes/[your-content-type-name].js` 文件中找到的 `config` 对象中,定义你希望中间件应用的动作键(`find`、`findOne`、`create`、`update`、`delete` 等),并为这些路由声明 `isOwner` 中间件。

例如,如果你希望允许 GET 请求(对应 `find` 和 `findOne` 动作)和 POST 请求(即 `create` 动作)对任何用户在 `restaurant` API 中的 `restaurant` 内容类型生效,但希望将 PUT(即 `update` 动作)和 DELETE 请求限制为仅对创建该条目的用户生效,你可以在 `src/api/restaurant/routes/restaurant.js` 文件中使用以下代码: ```js title="src/api/restaurant/routes/restaurant.js" /** * restaurant router */ const { createCoreRouter } = require("@strapi/strapi").factories; module.exports = createCoreRouter("api::restaurant.restaurant", { config: { update: { middlewares: ["api::restaurant.is-owner"], }, delete: { middlewares: ["api::restaurant.is-owner"], }, }, }); ``` :::info 你可以在 [路由文档](/cms/backend-customization/routes) 中找到有关路由中间件的更多信息。 🌐 You can find more information about route middlewares in the [routes documentation](/cms/backend-customization/routes). ::: # 模型 Source: https://docs.strapi.io/cms/backend-customization/models # 模型 {#models} 🌐 Models 由于 Strapi 是一个无头内容管理系统(CMS),为内容创建内容结构是使用该软件时最重要的方面之一。模型定义了内容结构的表示。 🌐 As Strapi is a headless Content Management System (CMS), creating a content structure for the content is one of the most important aspects of using the software. Models define a representation of the content structure. Strapi 有 2 种不同类型的模型: 🌐 There are 2 different types of models in Strapi: - 内容类型,可以是集合类型或单一类型,具体取决于它们管理的条目数量, - 以及可在多种内容类型中重复使用的内容结构组件。 如果你刚刚开始,可以直接在管理面板中使用 [Content-type Builder](/cms/features/content-type-builder) 生成一些模型。这种用户界面承担了许多验证任务,并展示了创建内容结构的所有可用选项。然后可以使用此文档在代码层面上查看生成的模型映射。 🌐 If you are just starting out, it is convenient to generate some models with the [Content-type Builder](/cms/features/content-type-builder) directly in the admin panel. The user interface takes over a lot of validation tasks and showcases all the options available to create the content's content structure. The generated model mappings can then be reviewed at the code level using this documentation. ## 模型创建 {#model-creation} 🌐 Model creation 内容类型和组件模型的创建和存储方式不同。 🌐 Content-types and components models are created and stored differently. ### 内容类型 {#content-types} 🌐 Content-types 可以在 Strapi 中创建内容类型: 🌐 Content-types in Strapi can be created: - 在管理面板的[内容类型构建器](/cms/features/content-type-builder)中, - 或者使用 [Strapi 的交互式 CLI `strapi generate`](/cms/cli#strapi-generate) 命令。 内容类型使用以下文件: 🌐 The content-types use the following files: - `schema.json` 用于模型的 [schema](#model-schema) 定义。(自动生成,在使用任一方法创建内容类型时) - `lifecycles.js` 用于 [生命周期钩子](#lifecycle-hooks)。此文件必须手动创建。 这些模型文件存储在 `./src/api/[api-name]/content-types/[content-type-name]/` 中,任何在这些文件夹中找到的 JavaScript 或 JSON 文件都将被加载为内容类型的模型(参见 [项目结构](/cms/project-structure))。 🌐 These models files are stored in `./src/api/[api-name]/content-types/[content-type-name]/`, and any JavaScript or JSON file found in these folders will be loaded as a content-type's model (see [project structure](/cms/project-structure)). :::note 在启用了 [TypeScript](/cms/typescript.md) 的项目中,可以使用 `ts:generate-types` 命令生成模式类型定义。 🌐 In [TypeScript](/cms/typescript.md)-enabled projects, schema typings can be generated using the `ts:generate-types` command. ::: ### 组件 {#components-creation} 🌐 Components 组件模型无法使用 CLI 工具创建。请使用 [内容类型构建器](/cms/features/content-type-builder) 或手动创建它们。 🌐 Component models can't be created with CLI tools. Use the [Content-type Builder](/cms/features/content-type-builder) or create them manually. 组件模型存储在 `./src/components` 文件夹中。每个组件必须位于一个子文件夹内,该子文件夹的名称应与组件所属的类别相同(参见 [项目结构](/cms/project-structure))。 🌐 Components models are stored in the `./src/components` folder. Every component has to be inside a subfolder, named after the category the component belongs to (see [project structure](/cms/project-structure)). ## 模型架构 {#model-schema} 🌐 Model schema 一个模型的 `schema.json` 文件包含: 🌐 The `schema.json` file of a model consists of: - [设置](#model-settings),例如模型表示的内容类型或应存储数据的表名, - [信息](#model-information),主要用于在管理面板中显示模型并通过 REST 和 GraphQL API 访问它, - [属性](#model-attributes),描述模型的内容结构, - 以及 [options](#model-options) 用于定义模型上的特定行为。 ### 模型设置 {#model-settings} 🌐 Model settings 模型的常规设置可以使用以下参数进行配置: 🌐 General settings for the model can be configured with the following parameters: | 参数 | 类型 | 描述 || --- | --- | --- || `collectionName` | 字符串 | 数据应存储的数据库表名称 || `kind`

_可选,
仅用于内容类型_ | 字符串 | 定义内容类型是否为:
  • 集合类型(`collectionType`)
  • 或单一类型(`singleType`)
| ```json // ./src/api/[api-name]/content-types/restaurant/schema.json { "kind": "collectionType", "collectionName": "Restaurants_v1", } ``` ### 模型信息 {#model-information} 🌐 Model information 模型模式中的 `info` 键描述了用于在管理面板中显示模型以及通过内容 API 访问模型的信息。它包括以下参数: 🌐 The `info` key in the model's schema describes information used to display the model in the admin panel and access it through the Content API. It includes the following parameters: | 参数 | 类型 | 描述 || --- | --- | --- || `displayName` | 字符串 | 在管理面板中使用的默认名称 || `singularName` | 字符串 | 内容类型名称的单数形式。
用于生成 API 路由和数据库/表集合。

应使用 kebab-case 格式。 || `pluralName` | 字符串 | 内容类型名称的复数形式。
用于生成 API 路由和数据库/表集合。

应使用 kebab-case 格式。 || `description` | 字符串 | 模型的描述 | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" "info": { "displayName": "Restaurant", "singularName": "restaurant", "pluralName": "restaurants", "description": "" }, ``` ### 模型属性 {#model-attributes} 🌐 Model attributes 模型的内容结构由一系列属性组成。每个属性都有一个 `type` 参数,用于描述其性质,并将该属性定义为简单的数据片段或 Strapi 使用的更复杂结构。 🌐 The content structure of a model consists of a list of attributes. Each attribute has a `type` parameter, which describes its nature and defines the attribute as a simple piece of data or a more complex structure used by Strapi. 有多种类型的属性可用: 🌐 Many types of attributes are available: - 标量类型(例如字符串、日期、数字、布尔值等), - Strapi 特有的类型,例如: - `media` 用于通过 [媒体库](/cms/features/content-type-builder#media) 上传的文件 - `relation` 用于描述内容类型之间的 [关系](#relations) - `customField` 用于描述 [自定义字段](#custom-fields) 及其特定键 - `component` 用于定义一个 [组件](#components-json)(即可在多种内容类型中使用的内容结构) - `dynamiczone` 用于定义一个 [动态区域](#dynamic-zones)(即基于组件列表的灵活空间) - 以及 `locale` 和 `localizations` 类型,仅由 [国际化 (i18n) 插件](/cms/features/internationalization) 使用 属性的 `type` 参数应为以下值之一: 🌐 The `type` parameter of an attribute should be one of the following values: | 类型类别 | 可用类型 ||------|-------|| 字符串类型 |
  • `string`
  • `text`
  • `richtext`
  • `enumeration`
  • `email`
  • `password`
  • [`uid`](#uid-type)
|| 日期类型 |
  • `date`
  • `time`
  • `datetime`
  • `timestamp`
|| 数字类型 |
  • `integer`
  • `biginteger`
  • `float`
  • `decimal`
|| 其他通用类型 |
  • `boolean`
  • `json`
|| Strapi 独有的特殊类型 |
  • `media`
  • [`relation`](#relations)
  • [`customField`](#custom-fields)
  • [`component`](#components-json)
  • [`dynamiczone`](#dynamic-zones)
|| 国际化 (i18n) 相关类型

_仅在内容类型启用了 [i18n](/cms/features/internationalization) 时可用_|
  • `locale`
  • `localizations`
| #### 验证 {#validations} 🌐 Validations 可以使用以下参数将基本验证应用于属性: 🌐 Basic validations can be applied to attributes using the following parameters: | 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || `required` | 布尔值 | 如果 `true`,为此属性添加必填验证器 | `false` || `max` | 整数 | 检查值是否大于或等于给定的最大值 | - || `min` | 整数 | 检查值是否小于或等于给定的最小值 | - || `minLength` | 整数 | 字段输入值的最小字符数 | - || `maxLength` | 整数 | 字段输入值的最大字符数 | - || `private` | 布尔值 | 如果 `true`,该属性将从服务器响应中移除。

💡 这对于隐藏敏感数据很有用。 | `false` || `configurable` | 布尔值 | 如果 `false`,该属性无法通过内容类型构建器插件进行配置。 | `true` | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { // ... "attributes": { "title": { "type": "string", "minLength": 3, "maxLength": 99, "unique": true }, "description": { "default": "My description", "type": "text", "required": true }, "slug": { "type": "uid", "targetField": "title" } // ... } } ``` #### 数据库验证和设置 {#database-validations-and-settings} 🌐 Database validations and settings :::caution 🚧 This API is considered experimental. 这些设置应该保留给高级使用,因为它们可能会导致某些功能失效。目前没有计划让这些设置稳定。 🌐 These settings should be reserved to an advanced usage, as they might break some features. There are no plans to make these settings stable. ::: 数据库验证和设置是直接传递给 `tableBuilder` Knex.js 函数的自定义选项,用于架构迁移期间。数据库验证允许对设置自定义列设置进行高级控制。以下选项在每个属性的 `column: {}` 对象中设置: 🌐 Database validations and settings are custom options passed directly onto the `tableBuilder` Knex.js function during schema migrations. Database validations allow for an advanced degree of control for setting custom column settings. The following options are set in a `column: {}` object per attribute: | 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || `name` | 字符串 | 更改数据库中列的名称 | - || `defaultTo` | 字符串 | 设置数据库的 `defaultTo`,通常与 `notNullable` 一起使用 | - || `notNullable` | 布尔值 | 设置数据库的 `notNullable`,确保列不能为空 | `false` || `unsigned` | 布尔值 | 仅适用于数字列,移除允许负数的功能,但将最大长度加倍 | `false` || `unique` | 布尔值 | 强制对已发布条目执行数据库级唯一性检查。当启用“草稿与发布”功能时,草稿保存会跳过检查,因此仅在发布时重复才会失败 | `false` || `type` | 字符串 | 更改数据库类型,如果 `type` 有参数,应在 `args` 中传入 | - || `args` | 数组 | 传递给 Knex.js 函数的参数,可更改如 `type` 的内容 | `[]` | :::caution Draft & Publish and `unique` 当启用 [Draft & Publish](/cms/features/draft-and-publish) 时,Strapi 会在条目被保存为草稿时故意跳过 `unique` 验证。因此,重复内容在发布之前不会被检测到,此时数据库约束会触发错误,即使 UI 之前对于草稿显示了“已保存文档”。 🌐 When [Draft & Publish](/cms/features/draft-and-publish) is enabled, Strapi intentionally skips `unique` validations while an entry is saved as a draft. Duplicates therefore remain undetected until publication, at which point the database constraint triggers an error even though the UI previously displayed “Saved document” for the drafts. 为避免意外发布失败: 🌐 To avoid unexpected publication failures: - 禁用必须保持全局唯一的内容类型的“草稿和发布”功能, - 或添加自定义验证(例如生命周期钩子或中间件),在保存前检查草稿是否重复, - 或者依赖自动生成的唯一标识符,例如 `uid` 字段和文档编辑规范。 ::: ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { // ... "attributes": { "title": { "type": "string", "minLength": 3, "maxLength": 99, "unique": true, "column": { "unique": true // enforce database unique also } }, "description": { "default": "My description", "type": "text", "required": true, "column": { "defaultTo": "My description", // set database level default "notNullable": true // enforce required at database level, even for drafts } }, "rating": { "type": "decimal", "default": 0, "column": { "defaultTo": 0, "type": "decimal", // using the native decimal type but allowing for custom precision "args": [ 6,1 // using custom precision and scale ] } } // ... } } ``` #### `uid` 类型 {#uid-type} 🌐 `uid` type `uid` 类型用于在管理面板中自动预填字段值,使用唯一标识符(UID)(例如文章的 slug),基于两个可选参数: 🌐 The `uid` type is used to automatically prefill the field value in the admin panel with a unique identifier (UID) (e.g. slugs for articles) based on 2 optional parameters: - `targetField`(字符串):如果使用,定义为目标的字段的值将用于自动生成 UID。 - `options`(字符串):如果使用,UID 将基于传递给 #### 自定义字段 {#custom-fields} 🌐 Custom fields [自定义字段](/cms/features/custom-fields) 通过向内容类型添加新类型的字段来扩展 Strapi 的功能。自定义字段在模型的 [属性](#model-attributes) 中使用 `type: customField` 明确定义。 自定义字段的属性还显示以下特性: 🌐 Custom fields' attributes also show the following specificities: - 一个 `customField` 属性,其值作为唯一标识符,用于指示应使用哪个已注册的自定义字段。其值如下: - 如果插件创建了自定义字段,则使用 `plugin::plugin-name.field-name` 格式 - 或者用于当前 Strapi 应用特定自定义字段的 `global::field-name` 格式 - 以及额外的参数,这取决于在注册自定义字段时定义的内容(参见[自定义字段文档](/cms/features/custom-fields))。 ```json title="./src/api/[apiName]/[content-type-name]/content-types/schema.json" { // … "attributes": { "attributeName": { // attributeName would be replaced by the actual attribute name "type": "customField", "customField": "plugin::color-picker.color", "options": { "format": "hex" } } } // … } ``` #### 组件 {#components-json} 🌐 Components 组件字段在内容类型和组件结构之间创建关系。组件在模型的 [attributes](#model-attributes) 中通过 `type: 'component'` 明确定义,并接受以下附加参数: 🌐 Component fields create a relation between a content-type and a component structure. Components are explicitly defined in the [attributes](#model-attributes) of a model with `type: 'component'` and accept the following additional parameters: | 参数 | 类型 | 描述 || --- | --- | --- || `repeatable` | 布尔值 | 根据组件是否可重复,可能是 `true` 或 `false` || `component` | 字符串 | 定义相应的组件,遵循此格式:
`.` | ```json title="./src/api/[apiName]/restaurant/content-types/schema.json" { "attributes": { "openinghours": { "type": "component", "repeatable": true, "component": "restaurant.openinghours" } } } ``` #### 动态区域 {#dynamic-zones} 🌐 Dynamic zones 动态区域创建了一个灵活的空间,用于根据混合的[组件](#components-json)列表来编排内容。 🌐 Dynamic zones create a flexible space in which to compose content, based on a mixed list of [components](#components-json). 动态区域在模型的 [attributes](#model-attributes) 中用 `type: 'dynamiczone'` 明确定义。它们还接受一个 `components` 数组,其中每个组件的名称应遵循以下格式:`.`。 🌐 Dynamic zones are explicitly defined in the [attributes](#model-attributes) of a model with `type: 'dynamiczone'`. They also accept a `components` array, where each component should be named following this format: `.`. ```json title="./src/api/[api-name]/content-types/article/schema.json" { "attributes": { "body": { "type": "dynamiczone", "components": ["article.slider", "article.content"] } } } ``` ### 模型选项 {#model-options} 🌐 Model options `options` 键用于定义特定行为,并接受以下参数: 🌐 The `options` key is used to define specific behaviors and accepts the following parameter: | 参数 | 类型 | 描述 | |---------------------|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | `privateAttributes` | 字符串数组 | 允许将一组属性视为私有,即使它们实际上并未在模型中定义为属性。它可以用于从 API 响应中移除它们的时间戳。

模型中定义的 `privateAttributes` 会与全局 Strapi 配置中定义的 `privateAttributes` 合并。 | | `draftAndPublish` | 布尔值 | 启用草稿和发布功能。

默认值:`true`(如果内容类型是通过交互式 CLI 创建,则为 `false`)。 | | `populateCreatorFields` | 布尔值 | 在 REST API 返回的响应中填充 `createdBy` 和 `updatedBy` 字段(更多详情参见[指南](/cms/api/rest/guides/populate-creator-fields))。

默认值:`false`。 | ```json title="./src/api/[api-name]/content-types/restaurant/schema.json" { "options": { "privateAttributes": ["id", "createdAt"], "draftAndPublish": true } } ``` ### 插件选项 {#plugin-options} 🌐 Plugin options `pluginOptions` 是一个可选对象,允许插件为模型或特定属性存储配置。 | 键 | 值 | 描述 ||---------------------------|-------------------------------|--------------------------------------------------------|| `i18n` | `localized: true` | 启用本地化。 || `content-manager` | `visible: false` | 在管理员面板中从内容管理器隐藏。 || `content-type-builder` | `visible: false` | 在管理员面板中从内容类型构建器隐藏。 | ```json title="./src/api/[api-name]/content-types/[content-type-name]/schema.json" { "attributes": { "name": { "pluginOptions": { "i18n": { "localized": true } }, "type": "string", "required": true }, "slug": { "pluginOptions": { "i18n": { "localized": true } }, "type": "uid", "targetField": "name", "required": true } // …additional attributes } } ``` ## 生命周期钩子 {#lifecycle-hooks} 🌐 Lifecycle hooks 生命周期钩子是当 Strapi 查询被调用时触发的函数。当通过管理面板管理内容或使用 `queries` 开发自定义代码时,它们会自动触发。 🌐 Lifecycle hooks are functions that get triggered when Strapi queries are called. They are triggered automatically when managing content through the administration panel or when developing custom code using `queries`· 生命周期钩子可以通过声明或编程方式自定义。 🌐 Lifecycle hooks can be customized declaratively or programmatically. :::caution 当直接使用 使用数据库层 API,还可以注册订阅者并以编程方式监听事件: 🌐 Using the database layer API, it's also possible to register a subscriber and listen to events programmatically: ```js title="./src/index.js" module.exports = { async bootstrap({ strapi }) { // registering a subscriber strapi.db.lifecycles.subscribe({ models: [], // optional; beforeCreate(event) { const { data, where, select, populate } = event.params; event.state = 'doStuffAfterWards'; }, afterCreate(event) { if (event.state === 'doStuffAfterWards') { } const { result, params } = event; // do something to the result }, }); // generic subscribe for generic handling strapi.db.lifecycles.subscribe((event) => { if (event.action === 'beforeCreate') { // do something } }); } } ``` # 政策 Source: https://docs.strapi.io/cms/backend-customization/policies # 政策 {#policies} 🌐 Policies 策略是在每个请求到达[控制器](/cms/backend-customization/controllers)之前执行特定逻辑的函数。它们主要用于保护业务逻辑。 🌐 Policies are functions that execute specific logic on each request before it reaches the [controller](/cms/backend-customization/controllers). They are mostly used for securing business logic. Strapi 项目的每个[路由](/cms/backend-customization/routes)都可以关联到一组策略。例如,一个名为 `is-admin` 的策略可以检查请求是否由管理员用户发送,并限制对关键路由的访问。 🌐 Each [route](/cms/backend-customization/routes) of a Strapi project can be associated to an array of policies. For example, a policy named `is-admin` could check that the request is sent by an admin user, and restrict access to critical routes. 策略可以是全局的或有范围的。[全局策略](#global-policies)可以关联到项目中的任何路由。有范围的策略只适用于特定的[API](#api-policies)或[插件](#plugin-policies),并应存放在相应的`./src/api//policies/`或`./src/plugins//policies/`文件夹下。
Simplified Strapi backend diagram with routes and policies highlighted
该图表示请求在 Strapi 后端传输的简化版本,并突出了策略和路由。后端自定义介绍页面包括一个完整的, 交互式图表
## 实现 {#implementation} 🌐 Implementation 可以实现一项新政策: 🌐 A new policy can be implemented: - 使用 [交互式 CLI 命令 `strapi generate`](/cms/cli#strapi-generate) - 或者通过在相应的文件夹中创建一个 JavaScript 文件手动完成(参见 [项目结构](/cms/project-structure)): - `./src/policies/` 用于全球政策 - `./src/api/[api-name]/policies/` 用于 API 策略 - `./src/plugins/[plugin-name]/policies/` 用于插件策略
全球政策实现示例: 🌐 Global policy implementation example: `policyContext` 是 [controller](/cms/backend-customization/controllers) 上下文的一个封装。它增加了一些逻辑,这些逻辑对于在 REST 和 GraphQL 中实现策略可能很有用。
可以使用 `config` 对象配置策略: 🌐 Policies can be configured using a `config` object: ## 使用 {#usage} 🌐 Usage 要将策略应用到路由,请将它们添加到路由的配置对象中(参见 [路由文档](/cms/backend-customization/routes#policies))。 🌐 To apply policies to a route, add them to its configuration object (see [routes documentation](/cms/backend-customization/routes#policies)). 策略根据其范围有不同的调用方式: 🌐 Policies are called different ways depending on their scope: - 使用 `global::policy-name` 用于 [全局策略](#global-policies) - 使用 `api::api-name.policy-name` 用于 [API 政策](#api-policies) - 使用 `plugin::plugin-name.policy-name` 用于 [插件政策](#plugin-policies) :::tip 要列出所有可用的策略,请运行 `yarn strapi policies:list`。 🌐 To list all the available policies, run `yarn strapi policies:list`. ::: ### 全球政策 {#global-policies} 🌐 Global policies 全局策略可以与项目中的任何路由关联。 🌐 Global policies can be associated to any route in a project. ### 插件政策 {#plugin-policies} 🌐 Plugin policies 插件可以向应用添加并公开策略。例如,[用户与权限功能](/cms/features/users-permissions) 配备了策略,以确保用户已通过身份验证或拥有执行某个操作的权限: 🌐 Plugins can add and expose policies to an application. For example, the [Users & Permissions feature](/cms/features/users-permissions) comes with policies to ensure that the user is authenticated or has the rights to perform an action: ### API 政策 {#api-policies} 🌐 API policies API 策略与声明它们的 API 中定义的路由相关联。 🌐 API policies are associated to the routes defined in the API where they have been declared. 要在另一个 API 中使用策略,请使用以下语法引用它:`api::[apiName].[policyName]`: 🌐 To use a policy in another API, reference it with the following syntax: `api::[apiName].[policyName]`: # 请求与响应 Source: https://docs.strapi.io/cms/backend-customization/requests-responses # 请求与响应 {#requests-and-responses} 🌐 Requests and Responses Strapi 后端服务器基于 。当你通过 [REST API](/cms/api/rest) 发送请求时,一个上下文对象(`ctx`)会传递给 Strapi 后端的每个元素(例如,[policies](/cms/backend-customization/policies)、[controllers](/cms/backend-customization/controllers)、[services](/cms/backend-customization/services))。 `ctx` 包含 3 个主要对象: - [`ctx.request`](#ctxrequest) 了解关于发起 API 请求的客户端发送的请求的信息, - [`ctx.state`](#ctxstate) 了解有关请求在 Strapi 后端状态的信息, - 以及 [`ctx.response`](#ctxresponse) 获取有关服务器将返回的响应的信息。 :::tip 请求的上下文也可以通过代码中的任何位置使用 [`strapi.requestContext` 函数](#accessing-the-request-context-anywhere) 访问。 🌐 The request's context can also be accessed from anywhere in the code with the [`strapi.requestContext` function](#accessing-the-request-context-anywhere). ::: :::info 除了以下文档中描述的概念和参数外,你可能还会在 、 和 中找到额外的信息。 :::
Simplified Strapi backend diagram with requests and responses highlighted
该图表示请求在 Strapi 后端传输的简化版本,并突出了请求和响应。后端自定义介绍页面包括一个完整的、 交互式图表
## `ctx.request` `ctx.request` 对象包含以下参数: 🌐 The `ctx.request` object contains the following parameters: | 参数 | 描述 | 类型 | | --- | --- | --- | | `ctx.request.body` | 正文的解析版本。 | `Object` | | `ctx.request.files` | 随请求发送的文件。 | `Array` | | `ctx.request.headers` | 随请求发送的头信息。 | `Object` | | `ctx.request.host` | URL 的主机部分,包括端口。 | `String` | | `ctx.request.hostname`| URL 的主机部分,不包括端口。 | `String` | | `ctx.request.href` | 请求资源的完整 URL,包括协议、域名、端口(如果指定)、路径和查询参数。 | `String` | | `ctx.request.ip` | 发送请求的人的IP。| `String` | | `ctx.request.ips` | 当 `X-Forwarded-For` 存在并且 `app.proxy` 启用时,将返回一个 IP 数组,按从上游到下游的顺序排列。

例如,如果值为 "client, proxy1, proxy2",你将收到 `["client", "proxy1", "proxy2"]` 数组。 | `Array` | | `ctx.request.method` | 请求方法(例如,`GET`、`POST`)。 | `String` | | `ctx.request.origin` | 第一个 `/` 之前的 URL 部分。 | `String` | | `ctx.request.params` | 在URL中发送的参数。

例如,如果内部URL是 `/restaurants/:id`,在实际请求中替换 `:id` 的任何内容都可以通过 `ctx.request.params.id` 访问。 | `Object` | | `ctx.request.path` | 请求资源的路径,不包括查询参数。 | `String` | | `ctx.request.protocol`| 使用的协议(例如,`https` 或 `http`)。 | `String` | | `ctx.request.query` | Strapi特定的[查询参数](#ctxrequestquery)。 | `Object` | | `ctx.request.subdomains`| 包含在URL中的子域名。

例如,如果域名是 `tobi.ferrets.example.com`,则值为以下数组:`["ferrets", "tobi"]`。 | `Array` | | `ctx.request.url` | 请求资源的路径和查询参数,不包括协议、域名和端口。 | `String` |
协议、来源、URL、href、路径、主机和主机名之间的区别: 对于发送到 `https://example.com:1337/api/restaurants?id=123` URL 的 API 请求,`ctx.request` 对象的不同参数返回如下内容: 🌐 Given an API request sent to the `https://example.com:1337/api/restaurants?id=123` URL, here is what different parameters of the `ctx.request` object return: | 参数 | 返回值 || --- | --- || `ctx.request.href` | `https://example.com:1337/api/restaurants?id=123` || `ctx.request.protocol` | `https` || `ctx.request.host` | `localhost:1337` || `ctx.request.hostname` | `localhost` || `ctx.request.origin` | `https://example.com:1337` || `ctx.request.url` | `/api/restaurants?id=123` || `ctx.request.path` | `/api/restaurants` |
### `ctx.request.query` `ctx.request` 提供了一个 `query` 对象,用于访问 Strapi 查询参数。下表列出了可用参数、简短描述以及相关 REST API 文档部分的链接(更多信息请参见 [REST API 参数](/cms/api/rest/parameters)): | 参数 | 描述 | 类型 | | ---| --- | --- | | `ctx.request.query`
`ctx.query` | 整个查询对象。 | `Object` | | `ctx.request.query.sort` | 用于 [排序响应](/cms/api/rest/sort-pagination.md#sorting) 的参数 | `String` 或 `Array` | | `ctx.request.query.filters` | 用于[筛选响应](/cms/api/rest/filters)的参数 | `Object` | | `ctx.request.query.populate` | 用于[填充关联、组件或动态区域](/cms/api/rest/populate-select#population)的参数 | `String` 或 `Object` | | `ctx.request.query.fields` | [仅选择要随响应返回的特定字段](/cms/api/rest/populate-select#field-selection) 的参数 | `Array` | | `ctx.request.query.pagination` | 用于[翻页浏览条目](/cms/api/rest/sort-pagination.md#pagination)的参数 | `Object` | | `ctx.request.query.publicationState` | 参数用于[选择草稿和发布状态](/cms/api/rest/status) | `String` | | `ctx.request.query.locale` | 参数,用于[选择一个或多个语言环境](/cms/api/rest/locale) | `String` 或 `Array` | ## `ctx.state` `ctx.state` 对象提供对 Strapi 后端请求状态的访问,包括关于 [用户](#ctxstateuser)、[认证](#ctxstateauth)、[路由](#ctxstateroute) 的具体值: 🌐 The `ctx.state` object gives access to the state of the request within the Strapi back end, including specific values about the [user](#ctxstateuser), [authentication](#ctxstateauth), [route](#ctxstateroute): | 参数 | 描述 | 类型 || ---|---------------------------------------------------------------------------- | --- || `ctx.state.isAuthenticated`| 返回当前用户是否以任何方式经过身份验证。 | `Boolean` | ### `ctx.state.user` `ctx.state.user` 对象提供对执行请求的用户信息的访问,并包括以下参数: 🌐 The `ctx.state.user` object gives access to information about the user performing the request and includes the following parameters: | 参数 | 描述 | 类型 || --- | --- | --- || `ctx.state.user` | 用户的信息。只填写一个关系。 | `Object` || `ctx.state.user.role` | 用户的角色 | `Object` | ### `ctx.state.auth` `ctx.state.auth` 对象提供与身份验证相关的信息访问,包括以下参数: 🌐 The `ctx.state.auth` object gives access to information related to the authentication and includes the following parameters: | 参数 | 描述 | 类型 || ---| --- | --- || `ctx.state.auth.strategy` | 当前使用的认证策略的信息([用户与权限插件](/cms/features/users-permissions) 或 [API 令牌](/cms/features/api-tokens)) | `Object` || `ctx.state.auth.strategy.name`| 当前使用的策略名称 | `String` || `ctx.state.auth.credentials` | 用户的凭证 | `String` | ### `ctx.state.route` `ctx.state.route` 对象提供对与当前路由相关的信息的访问,包括以下参数: 🌐 The `ctx.state.route` object gives access to information related to the current route and includes the following parameters: | 参数 | 描述 | 类型 || ---| --- | --- || `ctx.state.route.method`| 用于访问当前路由的方法。 | `String` || `ctx.state.route.path`| 当前路由的路径。 | `String` || `ctx.state.route.config`| 关于当前路由的配置信息。 | `Object` || `ctx.state.route.handler`| 当前路由的处理程序(控制器)。 | `Object` || `ctx.state.route.info`| 关于当前路由的附加信息,例如 apiName 和 API 请求类型。 | `Object` || `ctx.state.route.info.apiName`| 所使用 API 的名称。 | `String` || `ctx.state.route.info.type`| 所使用 API 的类型。 | `String` | ## `ctx.response` `ctx.response` 对象提供对服务器将返回的响应相关信息的访问,并包括以下参数: 🌐 The `ctx.response` object gives access to information related to the response that the server will return and includes the following parameters: | 参数 | 描述 | 类型 | | ---| --- | --- | | `ctx.response.body`| 响应的内容。 | `Any` | | `ctx.response.status` | 响应的状态码。 | `Integer` | | `ctx.response.message`| 响应的状态消息。

默认情况下,`response.message` 与 `response.status` 相关联。 | `String` | | `ctx.response.header`
`ctx.response.headers`| 随响应发送的头信息。 | `Object` | | `ctx.response.length`| 当存在时,将 `` 头的值作为数字,或在可能时从 `ctx.body` 推断;否则,返回 `undefined`。 | `Integer` | | `ctx.response.redirect`
`ctx.response.redirect(url, [alt])` | 执行对 URL 的 `302` 重定向。字符串 “back” 被特殊处理以提供 Referrer 支持;当 Referrer 不存在时,使用 alt 或 “/”。

示例: `ctx.response.redirect('back', '/index.html');` | `Function` | | `ctx.response.attachment`

`ctx.response.attachment([filename], [options])` | 将 头设置为 "attachment",以提示客户端进行下载。可选地指定下载文件名和一些 。 | `Function` | | `ctx.response.type`| 头,不包含诸如 "charset" 之类的参数。 | `String` | | `ctx.response.lastModified`| 将 `` 头作为日期,如果它存在的话。 | `DateTime` | | `ctx.response.etag`| 设置响应的 ,包括封装的 s.
没有对应的 `response.etag` 获取器。 | `String` | ## 在任何地方访问请求上下文 {#accessing-the-request-context-anywhere} 🌐 Accessing the request context anywhere Strapi 公开了一种从代码中的任何位置访问当前请求上下文的方法(例如生命周期函数)。 🌐 Strapi exposes a way to access the current request context from anywhere in the code (e.g. lifecycle functions). 你可以按如下方式访问该请求: 🌐 You can access the request as follows: ```js const ctx = strapi.requestContext.get(); ``` 你应该只在 HTTP 请求上下文中调用的函数内部使用它。 🌐 You should only use this inside of functions that will be called in the context of an HTTP request. ```js // correct const service = { myFunction() { const ctx = strapi.requestContext.get(); console.log(ctx.state.user); }, }; // incorrect const ctx = strapi.requestContext.get(); const service = { myFunction() { console.log(ctx.state.user); }, }; ``` **示例:** ```js title="./api/test/content-types/article/lifecycles.js" module.exports = { beforeUpdate() { const ctx = strapi.requestContext.get(); console.log('User info in service: ', ctx.state.user); }, }; ``` :::note Strapi 使用 Node.js 的一个名为 的功能来使上下文在任何地方都可用。 ::: # 路线 Source: https://docs.strapi.io/cms/backend-customization/routes # 路线 {#routes} 🌐 Routes 发送到 Strapi 上任何 URL 的请求都由路由处理。默认情况下,Strapi 会为所有内容类型生成路由(请参阅 [REST API 文档](/cms/api/rest))。路由可以被 [添加](#implementation) 和配置: 🌐 Requests sent to Strapi on any URL are handled by routes. By default, Strapi generates routes for all the content-types (see [REST API documentation](/cms/api/rest)). Routes can be [added](#implementation) and configured: - 使用 [策略](#policies),这是一种阻止访问某个路线的方法, - 以及使用 [中间件](#middlewares),中间件是一种控制和改变请求流程及请求本身的方式。 一旦路由存在,访问它会执行由控制器处理的一些代码(参见 [控制器文档](/cms/backend-customization/controllers))。要查看所有现有路由及其层级顺序,你可以运行 `yarn strapi routes:list`(参见 [CLI 参考](/cms/cli))。 🌐 Once a route exists, reaching it executes some code handled by a controller (see [controllers documentation](/cms/backend-customization/controllers)). To view all existing routes and their hierarchal order, you can run `yarn strapi routes:list` (see [CLI reference](/cms/cli)). :::tip 如果你只是自定义 Strapi 为某个内容类型生成的默认控制器操作(`find`、`findOne`、`create`、`update` 或 `delete`),你可以保持路由不变。这些核心路由已经指向相同的处理程序名称,并会运行你新的控制器逻辑。只有在你需要一个全新的 HTTP 路径/方法或想要暴露自定义控制器操作时,才需要添加或编辑路由。 🌐 If you only customize the default controller actions (`find`, `findOne`, `create`, `update`, or `delete`) that Strapi generates for a content-type, you can leave the router as-is. Those core routes already target the same handler names and will run your new controller logic. Add or edit a route only when you need a brand-new HTTP path/method or want to expose a custom controller action. :::
Simplified Strapi backend diagram with routes highlighted
该图表示请求在 Strapi 后端传输的简化版本,并标出了路由。后端自定义介绍页面包括完整的、 交互式图表
## 实现 {#implementation} 🌐 Implementation 实现一个新路由包括在 `./src/api/[apiName]/routes` 文件夹中的路由文件中定义它(参见 [项目结构](/cms/project-structure))。 🌐 Implementing a new route consists in defining it in a router file within the `./src/api/[apiName]/routes` folder (see [project structure](/cms/project-structure)). 根据用例,有 2 种不同的路由文件结构: 🌐 There are 2 different router file structures, depending on the use case: - 配置[核心路由](#configuring-core-routers) - 或创建[自定义路由](#creating-custom-routers)。 ### 配置核心路由 {#configuring-core-routers} 🌐 Configuring core routers 核心路由(即 `find`、`findOne`、`create`、`update` 和 `delete`)对应于当创建新的 [内容类型](/cms/backend-customization/models#model-creation) 时 Strapi 自动创建的 [默认路由](/cms/api/rest#endpoints)。 🌐 Core routers (i.e. `find`, `findOne`, `create`, `update`, and `delete`) correspond to [default routes](/cms/api/rest#endpoints) automatically created by Strapi when a new [content-type](/cms/backend-customization/models#model-creation) is created. Strapi 提供了一个 `createCoreRouter` 工厂函数,它会自动生成核心路由并允许: 🌐 Strapi provides a `createCoreRouter` factory function that automatically generates the core routers and allows: - 将配置选项传递给每个路由 - 并禁用一些核心路由以[创建自定义路由](#creating-custom-routers)。 核心路由文件是一个 JavaScript 文件,导出对 `createCoreRouter` 调用的结果,该调用具有以下参数: 🌐 A core router file is a JavaScript file exporting the result of a call to `createCoreRouter` with the following parameters: | 参数 | 描述 | 类型 || --- | --- | --- || `prefix` | 允许传入自定义前缀,添加到该模型的所有路由(例如 `/test`) | `String` || `only` | 仅会加载的核心路由

数组中未包含的内容将被忽略。 | `Array` | -->| `except` | 不应加载的核心路由

在功能上与 `only` 参数相反。 | `Array` || `config` | 配置路由的 [策略](#policies)、[中间件](#middlewares) 和 [公共可用性](#public-routes) | `Object` |

通用实现示例: 🌐 Generic implementation example: 这仅允许在 `/restaurants` 路径上从核心 `find` [控制器](/cms/backend-customization/controllers) 进行 `GET` 请求而无需身份验证。当你在自定义路由中引用自定义控制器操作时,建议使用完整限定的 `api::..` 形式以便于理解(例如,`api::restaurant.restaurant.review`)。 ### 创建自定义路由 {#creating-custom-routers} 🌐 Creating custom routers 创建自定义路由包括创建一个导出对象数组的文件,每个对象都是具有以下参数的路由: 🌐 Creating custom routers consists in creating a file that exports an array of objects, each object being a route with the following parameters: | 参数 | 描述 | 类型 || --- | --- | --- || `method` | 路由关联的方法(例如 `GET`、`POST`、`PUT`、`DELETE` 或 `PATCH`) | `String` || `path` | 要访问的路径,以斜杠开头(例如 `/articles`) | `String` || `handler` | 当路由被访问时执行的函数。
使用完整限定语法 `api::api-name.controllerName.actionName`(或 `plugin::plugin-name.controllerName.actionName`)。遗留项目中也可使用简短形式 `.`。 | `String` || `config`

_可选_ | 用于处理路由的[策略](#policies)、[中间件](#middlewares)和[公开访问](#public-routes)的配置

| `Object` |
可以使用参数和正则表达式创建动态路由。这些参数将会在 `ctx.params` 对象中暴露。更多详情,请参阅
## 配置 {#configuration} 🌐 Configuration 核心路由和自定义路由都有相同的配置选项。路由配置在一个 `config` 对象中定义,该对象可以用来处理策略和中间件,或将路由设为公开。 🌐 Both [core routers](#configuring-core-routers) and [custom routers](#creating-custom-routers) have the same configuration options. The routes configuration is defined in a `config` object that can be used to handle [policies](#policies) and [middlewares](#middlewares) or to [make the route public](#public-routes). ### 政策 {#policies} 🌐 Policies 可以将[策略](/cms/backend-customization/policies)添加到路由配置中: - 通过指向在 `./src/policies` 中注册的策略,无论是否传递自定义配置 - 或者通过直接声明策略实现,将其作为一个函数,该函数以 `policyContext` 扩展 ### 中间件 {#middlewares} 🌐 Middlewares 可以将[中间件](/cms/backend-customization/middlewares)添加到路由配置中: - 通过指向在 `./src/middlewares` 中注册的中间件,无论是否传递自定义配置 - 或者直接通过声明中间件实现,作为一个函数,该函数以 ### 公共路线 {#public-routes} 🌐 Public routes 默认情况下,路由受 Strapi 的身份验证系统保护,该系统基于[API 令牌](/cms/features/api-tokens)或使用[用户与权限插件](/cms/features/users-permissions)。 🌐 By default, routes are protected by Strapi's authentication system, which is based on [API tokens](/cms/features/api-tokens) or on the use of the [Users & Permissions plugin](/cms/features/users-permissions). 在某些情况下,将某条路由公开并在正常的 Strapi 身份验证系统之外控制访问可能是有用的。这可以通过将路由的 `auth` 配置参数设置为 `false` 来实现: 🌐 In some scenarios, it can be useful to have a route publicly available and control the access outside of the normal Strapi authentication system. This can be achieved by setting the `auth` configuration parameter of a route to `false`: ## 自定义内容 API 参数 {#custom-content-api-parameters} 🌐 Custom Content API parameters 你可以通过在 [register](/cms/configurations/functions#register) 生命周期中注册,将允许在内容 API 路由上的 `query` 和 body 参数扩展。注册的参数随后会像核心参数一样被验证和清理。客户端可以发送额外的查询键(例如 `?search=...`)或根级 body 键(例如 `clientMutationId`),而无需自定义路由或控制器。 🌐 You can extend the `query` and body parameters allowed on Content API routes by registering them in the [register](/cms/configurations/functions#register) lifecycle. Registered parameters are then validated and sanitized like core parameters. Clients can send extra query keys (e.g. `?search=...`) or root-level body keys (e.g. `clientMutationId`) without requiring custom routes or controllers. | 什么 | 哪里 ||------|--------|| 启用严格参数(拒绝未知的查询/主体键) | [API 配置](/cms/configurations/api):在 `./config/api.js`(或 `./config/api.ts`)中设置 `rest.strictParams: true`。 || 添加允许的参数(应用) | 在 `./src/index.js` 或 `./src/index.ts` 的 [注册](/cms/configurations/functions#register) 中调用 `addQueryParams` / `addInputParams`。 || 添加允许的参数(插件) | 在插件的 [注册](/cms/plugins-development/server-lifecycle#register) 生命周期中调用 `addQueryParams` / `addInputParams`。 | 当启用 `rest.strictParams` 时,仅接受核心参数和每个路由请求模式上的参数;你注册的参数会合并到该模式中。模式请使用来自 `@strapi/utils`(或 `zod/v4`)的 `z` 实例。 🌐 When `rest.strictParams` is enabled, only core parameters and parameters on each route's request schema are accepted; the parameters you register are merged into that schema. Use the `z` instance from `@strapi/utils` (or `zod/v4`) for schemas. ### `addQueryParams` `strapi.contentAPI.addQueryParams(options)` 注册额外的 `query` 参数。模式必须是标量或标量数组(字符串、数字、布尔值、枚举)。对于嵌套结构,请改用 `addInputParams`。每个条目可以有一个可选的 `matchRoute: (route) => boolean` 回调,仅将参数添加到回调返回 true 的路由。你不能将核心查询参数名称(例如 `filters`、`sort`、`fields`)注册为额外参数;它们是保留的。 ### `addInputParams` `strapi.contentAPI.addInputParams(options)` 注册额外的输入参数:请求体中的根级键(例如与 `data` 并列),可以使用任何 Zod 类型。可选的 `matchRoute` 回调的作用与 `addQueryParams` 相同。你不能将保留名称如 `id` 或 `documentId` 注册为输入参数。 ### `matchRoute` `matchRoute` 回调接收一个具有以下属性的 `route` 对象: 🌐 The `matchRoute` callback receives a `route` object with the following properties: - `route.method`:HTTP 方法(`'GET'`、`'POST'` 等) - `route.path`:路线路径 - `route.handler`:控制器操作字符串 - `route.info`:关于路线的元数据 例如,要仅针对 GET 路由,请使用 `matchRoute: (route) => route.method === 'GET'`。要仅针对路径包含 `articles` 的路由,请使用 `matchRoute: (route) => route.path.includes('articles')`。 🌐 For example, to target only GET routes, use `matchRoute: (route) => route.method === 'GET'`. To target only routes whose path includes `articles`, use `matchRoute: (route) => route.path.includes('articles')`. # 服务 Source: https://docs.strapi.io/cms/backend-customization/services # 服务 {#services} 🌐 Services 服务是一组可重用的功能。它们对于遵循“不要重复自己”(DRY)编程理念以及简化[控制器](/cms/backend-customization/controllers.md)的逻辑特别有用。 🌐 Services are a set of reusable functions. They are particularly useful to respect the "don’t repeat yourself" (DRY) programming concept and to simplify [controllers](/cms/backend-customization/controllers.md) logic.
Simplified Strapi backend diagram with services highlighted
该图表示请求在 Strapi 后端传递的简化版本,并高亮了服务。后端自定义介绍页面包括完整的、 交互式图表
## 实现 {#implementation} 🌐 Implementation 服务可以[手动生成或添加](#adding-a-new-service)。Strapi 提供了一个 `createCoreService` 工厂函数,能够自动生成核心服务,并允许构建自定义服务或[扩展或替换生成的服务](#extending-core-services)。 🌐 Services can be [generated or added manually](#adding-a-new-service). Strapi provides a `createCoreService` factory function that automatically generates core services and allows building custom ones or [extend or replace the generated services](#extending-core-services). ### 添加新服务 {#adding-a-new-service} 🌐 Adding a new service 可以实现一个新的服务: 🌐 A new service can be implemented: - 使用 [交互式 CLI 命令 `strapi generate`](/cms/cli#strapi-generate) - 或者通过在相应的文件夹中创建一个 JavaScript 文件手动完成(参见 [项目结构](/cms/project-structure.md)): - `./src/api/[api-name]/services/` 用于 API 服务 - 或用于[插件服务](/cms/plugins-development/server-controllers-services)的 `./src/plugins/[plugin-name]/services/`。 要手动创建一个服务,请导出一个工厂函数,该函数返回服务实现(即包含方法的对象)。该工厂函数接收 `strapi` 实例: 🌐 To manually create a service, export a factory function that returns the service implementation (i.e. an object with methods). This factory function receives the `strapi` instance: :::strapi Document Service API 要开始创建你自己的服务,请参阅 Strapi 的内置函数,详见 [文档服务 API](/cms/api/document-service) 文档。 🌐 To get started creating your own services, see Strapi's built-in functions in the [Document Service API](/cms/api/document-service) documentation. :::
自定义电子邮件服务示例(使用 Nodemailer) 服务的目标是存储可重复使用的函数。一个 `sendNewsletter` 服务可能在我们的代码库中从不同函数发送电子邮件时非常有用,这些函数有特定的用途: 🌐 The goal of a service is to store reusable functions. A `sendNewsletter` service could be useful to send emails from different functions in our codebase that have a specific purpose: 该服务现在可以通过 `strapi.service('api::restaurant.restaurant').sendNewsletter(...args)` 全局变量使用。它可以在代码库的其他部分使用,例如在以下控制器中: 🌐 The service is now available through the `strapi.service('api::restaurant.restaurant').sendNewsletter(...args)` global variable. It can be used in another part of the codebase, like in the following controller:
:::note 当创建新的 [内容类型](/cms/backend-customization/models.md#content-types) 时,Strapi 会生成一个带有占位符代码的通用服务,准备进行自定义。 🌐 When a new [content-type](/cms/backend-customization/models.md#content-types) is created, Strapi builds a generic service with placeholder code, ready to be customized. ::: ### 扩展核心服务 {#extending-core-services} 🌐 Extending core services 核心服务是为每种内容类型创建的,可以被[控制器](/cms/backend-customization/controllers.md)使用,以在 Strapi 项目中执行可重用的逻辑。核心服务可以自定义以实现你自己的逻辑。以下代码示例应能帮助你入门。 🌐 Core services are created for each content-type and could be used by [controllers](/cms/backend-customization/controllers.md) to execute reusable logic through a Strapi project. Core services can be customized to implement your own logic. The following code examples should help you get started. :::tip 核心服务可以完全通过[创建自定义服务](#adding-a-new-service)来替代,并将其命名为与核心服务相同(例如 `find`、`findOne`、`create`、`update` 或 `delete`)。 🌐 A core service can be replaced entirely by [creating a custom service](#adding-a-new-service) and naming it the same as the core service (e.g. `find`, `findOne`, `create`, `update`, or `delete`). :::
集合类型示例
单类型示例
## 使用 {#usage} 🌐 Usage 一旦服务被创建,就可以从[控制器](/cms/backend-customization/controllers.md)或其他服务访问它: 🌐 Once a service is created, it's accessible from [controllers](/cms/backend-customization/controllers.md) or from other services: ```js // access an API service strapi.service('api::apiName.serviceName').FunctionName(); // access a plugin service strapi.service('plugin::pluginName.serviceName').FunctionName(); ``` 在上面的语法示例中,`serviceName` 是 API 服务的服务文件名称,或者用于将服务文件导出到 `services/index.js` 的插件服务使用的名称。 🌐 In the syntax examples above, `serviceName` is the name of the service file for API services or the name used to export the service file to `services/index.js` for plugin services. :::tip 要列出所有可用的服务,请运行 `yarn strapi services:list`。 🌐 To list all the available services, run `yarn strapi services:list`. ::: ### 核心服务方法 {#core-service-methods} 🌐 Core service methods 使用 `createCoreService` 生成的服务继承了封装 [文档服务 API](/cms/api/document-service) 的方法。可用的方法取决于内容类型: 🌐 Services generated with `createCoreService` inherit methods that wrap the [Document Service API](/cms/api/document-service). The available methods depend on the content-type: #### 集合类型 {#collection-types} 🌐 Collection types | 方法 | 描述 | | --- | --- | | `find(params)` | [`findMany`](/cms/api/document-service#findmany) 的封装;返回文档的分页列表。 | | `findOne(documentId, params)` | [`findOne`](/cms/api/document-service#findone) 的封装器;通过其 `documentId` 返回单个文档。 | | `create(params)` | [`create`](/cms/api/document-service#create) 的封装器;创建一个新文档。 | | `update(documentId, params)` | [`update`](/cms/api/document-service#update) 的封装器;更新现有文档。 | | `delete(documentId, params)` | [`delete`](/cms/api/document-service#delete) 的封装器;删除一个文档。 | | `count(params)` | [`count`](/cms/api/document-service#count) 的封装器;返回匹配文档的数量。 | | `publish(documentId, params)` | [`publish`](/cms/api/document-service#publish) 的封装器;发布草稿文档。 | | `unpublish(documentId, params)` | [`unpublish`](/cms/api/document-service#unpublish) 的封装;取消发布文档。 | | `discardDraft(documentId, params)` | [`discardDraft`](/cms/api/document-service#discarddraft) 的封装器;删除草稿副本。 | #### 单一类型 {#single-types} 🌐 Single types | 方法 | 描述 || --- | --- || `find(params)` | 返回单个文档(内部使用 [`findFirst`](/cms/api/document-service#findfirst))。 || `createOrUpdate({ data, ...params })` | 如果文档不存在则创建,或更新文档(使用 [`update`](/cms/api/document-service#update))。 || `delete(params)` | 删除文档(使用 [`delete`](/cms/api/document-service#delete))。 || `count(params)` | 计算匹配过滤条件的文档数量(使用 [`count`](/cms/api/document-service#count))。 || `publish(params)` | 发布草稿文档(使用 [`publish`](/cms/api/document-service#publish))。 || `unpublish(params)` | 取消发布文档(使用 [`unpublish`](/cms/api/document-service#unpublish))。 || `discardDraft(params)` | 删除草稿副本(使用 [`discardDraft`](/cms/api/document-service#discarddraft))。 | #### 参数和默认行为 {#parameters-and-default-behavior} 🌐 Parameters and default behavior 核心服务方法接受与其底层的 [Document Service API](/cms/api/document-service) 调用相同的参数,例如 `fields`、`filters`、`sort`、`pagination`、`populate`、`locale` 和 `status`。当未提供 `status` 时,Strapi 会自动设置 `status: 'published'`,因此只返回已发布的内容。要查询草稿文档,请明确传递 `status: 'draft'` 或 Document Service 支持的其他值。 🌐 Core service methods accept the same parameters as their underlying [Document Service API](/cms/api/document-service) calls, such as `fields`, `filters`, `sort`, `pagination`, `populate`, `locale`, and `status`. When no `status` is provided, Strapi automatically sets `status: 'published'` so only published content is returned. To query draft documents, explicitly pass `status: 'draft'` or another value supported by the Document Service. `createCoreService` 工厂还提供了一个 `getFetchParams(params)` 辅助工具,它可以将控制器的查询对象转换为这些方法期望的参数格式。在重写核心方法以将清理后的参数传递给 `strapi.documents()` 时,可以重复使用此辅助工具。 🌐 The `createCoreService` factory also exposes a `getFetchParams(params)` helper that converts a controller's query object into the parameter format expected by these methods. This helper can be reused when overriding core methods to forward sanitized parameters to `strapi.documents()`. # 网络钩子 Source: https://docs.strapi.io/cms/backend-customization/webhooks # 网络钩子 {#webhooks} 🌐 Webhooks Webhook 是一种由应用使用的结构,用于通知其他应用某个事件已经发生。更准确地说,webhook 是用户定义的 HTTP 回调。使用 webhook 是告知第三方提供商开始某些处理(持续集成、构建、部署……)的好方法。 🌐 Webhook is a construct used by an application to notify other applications that an event occurred. More precisely, webhook is a user-defined HTTP callback. Using a webhook is a good way to tell third-party providers to start some processing (CI, build, deployment ...). Webhook 的工作方式是通过 HTTP 请求(通常是 POST 请求)向接收应用传递信息。 🌐 The way a webhook works is by delivering information to a receiving application through HTTP requests (typically POST requests). ## 用户内容类型的网页钩子 {#user-content-type-webhooks} 🌐 User content-type webhooks 为了防止无意中将任何用户的信息发送到其他应用,Webhooks 将不会对用户内容类型起作用。如果你需要向其他应用通知用户集合的更改,可以通过使用 `./src/index.js` 示例创建 [生命周期钩子](/cms/backend-customization/models#lifecycle-hooks) 来实现。 🌐 To prevent from unintentionally sending any user's information to other applications, Webhooks will not work for the User content-type. If you need to notify other applications about changes in the Users collection, you can do so by creating [Lifecycle hooks](/cms/backend-customization/models#lifecycle-hooks) using the `./src/index.js` example. ## 可用配置 {#available-configurations} 🌐 Available configurations 你可以在文件 `./config/server` 中设置 webhook 配置。 🌐 You can set webhook configurations inside the file `./config/server`. - `webhooks` - `defaultHeaders`:你可以为你的 webhook 请求设置默认头部。此选项会被 webhook 本身设置的头部覆盖。 **示例配置** ## Webhooks 安全 {#webhooks-security} 🌐 Webhooks security 大多数时候,Webhook 会向公共 URL 发出请求,因此有人可能会找到该 URL 并向其发送错误信息。 🌐 Most of the time, webhooks make requests to public URLs, therefore it is possible that someone may find that URL and send it wrong information. 为了防止这种情况发生,你可以发送带有身份验证令牌的头信息。使用管理面板时,你必须对每个 webhook 都这样做。 🌐 To prevent this from happening you can send a header with an authentication token. Using the Admin panel you would have to do it for every webhook. 另一种方法是定义 `defaultHeaders` 以添加到每个 webhook 请求中。 🌐 Another way is to define `defaultHeaders` to add to every webhook request. 你可以通过更新 `./config/server` 文件来配置这些全局头信息: 🌐 You can configure these global headers by updating the file at `./config/server`: 如果你自己开发 Webhook 处理程序,你现在可以通过读取标头来验证令牌。 🌐 If you are developing the webhook handler yourself you can now verify the token by reading the headers. ### 验证签名 {#verifying-signatures} 🌐 Verifying signatures 除了认证头之外,建议对 webhook 负载进行签名并在服务器端验证签名,以防止篡改和重放攻击。为此,你可以使用以下指南: 🌐 In addition to auth headers, it's recommended to sign webhook payloads and verify signatures server‑side to prevent tampering and replay attacks. To do so, you can use the following guidelines: - 生成共享密钥并将其存储在环境变量中。 - 让发送方对原始请求正文加上时间戳计算 HMAC(例如,SHA-256)。 - 在头信息中发送签名(和时间戳)(例如,`X‑Webhook‑Signature`,`X‑Webhook‑Timestamp`) - 收到请求后,重新计算 HMAC 并使用恒定时间检查进行比较。 - 如果签名无效或时间戳过旧,无法避免重放攻击,则拒绝请求。
示例:验证 HMAC 签名(Node.js) 这是一个最小的 Node.js 中间件示例(伪代码),显示 以下是一些额外的外部示例: 🌐 Here are a few additional external examples: - -
## 可用活动 {#available-events} 🌐 Available events 默认情况下,Strapi webhook 可以由以下事件触发: 🌐 By default Strapi webhooks can be triggered by the following events: | 名称 | 描述 | | --- | --- | | [`entry.create`](#entrycreate) | 当创建内容类型条目时触发。 | | [`entry.update`](#entryupdate) | 当内容类型条目被更新时触发。 | | [`entry.delete`](#entrydelete) | 当内容类型条目被删除时触发。 | |['entry.publish'](#entrypublish) |当发布内容类型条目时触发。\* | | [`entry.unpublish`](#entryunpublish) | 当内容类型条目被取消发布时触发。* | | [`media.create`](#mediacreate) | 当媒体被创建时触发。 | | [`media.update`](#mediaupdate) | 当媒体被更新时触发。 | | [`media.delete`](#mediadelete) | 当媒体被删除时触发。 | | [`review-workflows.updateEntryStage`](#review-workflowsupdateentrystage) | 当内容在审核阶段之间移动时触发(参见 [审核工作流程](/cms/features/review-workflows#configuration))。
此事件仅适用于 Strapi 的 版本。 | | [`releases.publish`](#releases-publish) | 当发布 Release 时触发(参见 [Releases](/cms/features/releases))。
此事件仅在 Strapi CMS 的 或 计划中可用。 | *仅当此内容类型上的 `draftAndPublish` 已启用时。 ## 有效载荷 {#payloads} 🌐 Payloads :::info 私有字段不会在有效负载中发送。 🌐 Private fields are not sent in the payload. ::: ### 标题 {#headers} 🌐 Headers 当有效负载传递到你的 webhook 的 URL 时,它将包含特定标头: 🌐 When a payload is delivered to your webhook's URL, it will contain specific headers: | 标题 | 描述 || --- | --- || `X-Strapi-Event` | 被触发的事件类型的名称。 | ### `entry.create` 创建新条目时会触发此事件。 🌐 This event is triggered when a new entry is created. **示例有效负载** ```json { "event": "entry.create", "createdAt": "2020-01-10T08:47:36.649Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:47:36.264Z", "cover": null, "images": [] } } ``` ### `entry.update` 当条目更新时会触发此事件。 🌐 This event is triggered when an entry is updated. **示例有效负载** ```json { "event": "entry.update", "createdAt": "2020-01-10T08:58:26.563Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "cover": null, "images": [] } } ``` ### `entry.delete` 当删除条目时会触发此事件。 🌐 This event is triggered when an entry is deleted. **示例有效负载** ```json { "event": "entry.delete", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "cover": null, "images": [] } } ``` ### `entry.publish` 发布条目时会触发此事件。 🌐 This event is triggered when an entry is published. **示例有效负载** ```json { "event": "entry.publish", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "publishedAt": "2020-08-29T14:20:12.134Z", "cover": null, "images": [] } } ``` ### `entry.unpublish` 当条目未发布时会触发此事件。 🌐 This event is triggered when an entry is unpublished. **示例有效负载** ```json { "event": "entry.unpublish", "createdAt": "2020-01-10T08:59:35.796Z", "model": "address", "entry": { "id": 1, "geolocation": {}, "city": "Paris", "postal_code": null, "category": null, "full_name": "Paris", "createdAt": "2020-01-10T08:47:36.264Z", "updatedAt": "2020-01-10T08:58:26.210Z", "publishedAt": null, "cover": null, "images": [] } } ``` ### `media.create` 当你在条目创建时或通过媒体界面上传文件时,会触发此事件。 🌐 This event is triggered when you upload a file on entry creation or through the media interface. **示例有效负载** ```json { "event": "media.create", "createdAt": "2020-01-10T10:58:41.115Z", "media": { "id": 1, "name": "image.png", "hash": "353fc98a19e44da9acf61d71b11895f9", "sha256": "huGUaFJhmcZRHLcxeQNKblh53vtSUXYaB16WSOe0Bdc", "ext": ".png", "mime": "image/png", "size": 228.19, "url": "/uploads/353fc98a19e44da9acf61d71b11895f9.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-10T10:58:41.095Z", "updatedAt": "2020-01-10T10:58:41.095Z", "related": [] } } ``` ### `media.update` 当你通过媒体接口更换媒体或更新媒体元数据时,会触发该事件。 🌐 This event is triggered when you replace a media or update the metadata of a media through the media interface. **示例有效负载** ```json { "event": "media.update", "createdAt": "2020-01-10T10:58:41.115Z", "media": { "id": 1, "name": "image.png", "hash": "353fc98a19e44da9acf61d71b11895f9", "sha256": "huGUaFJhmcZRHLcxeQNKblh53vtSUXYaB16WSOe0Bdc", "ext": ".png", "mime": "image/png", "size": 228.19, "url": "/uploads/353fc98a19e44da9acf61d71b11895f9.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-10T10:58:41.095Z", "updatedAt": "2020-01-10T10:58:41.095Z", "related": [] } } ``` ### `media.delete` 仅当你通过媒体接口删除媒体时才会触发该事件。 🌐 This event is triggered only when you delete a media through the media interface. **示例有效负载** ```json { "event": "media.delete", "createdAt": "2020-01-10T11:02:46.232Z", "media": { "id": 11, "name": "photo.png", "hash": "43761478513a4c47a5fd4a03178cfccb", "sha256": "HrpDOKLFoSocilA6B0_icA9XXTSPR9heekt2SsHTZZE", "ext": ".png", "mime": "image/png", "size": 4947.76, "url": "/uploads/43761478513a4c47a5fd4a03178cfccb.png", "provider": "local", "provider_metadata": null, "createdAt": "2020-01-07T19:34:32.168Z", "updatedAt": "2020-01-07T19:34:32.168Z", "related": [] } } ``` ### `review-workflows.updateEntryStage` 此事件仅适用于 Strapi 的 计划。
当内容被移动到新的审核阶段时,此事件将被触发(参见 [审核工作流](/cms/features/review-workflows#configuration))。 **示例有效负载** ```json { "event": "review-workflows.updateEntryStage", "createdAt": "2023-06-26T15:46:35.664Z", "model": "model", "uid": "uid", "entity": { "id": 2 }, "workflow": { "id": 1, "stages": { "from": { "id": 1, "name": "Stage 1" }, "to": { "id": 2, "name": "Stage 2" } } } } ``` ### `releases.publish` {#releases-publish} 当发布[release](/cms/features/releases)时,将触发该事件。 🌐 The event is triggered when a [release](/cms/features/releases) is published. **示例有效负载** ```json { "event": "releases.publish", "createdAt": "2024-02-21T16:45:36.877Z", "isPublished": true, "release": { "id": 2, "name": "Fall Winter highlights", "releasedAt": "2024-02-21T16:45:36.873Z", "scheduledAt": null, "timezone": null, "createdAt": "2024-02-21T15:16:22.555Z", "updatedAt": "2024-02-21T16:45:36.875Z", "actions": { "count": 1 } } } ``` ## Webhook 处理的最佳实践 {#best-practices-for-webhook-handling} 🌐 Best practices for webhook handling - 通过检查标头和有效负载签名来验证传入请求。 - 对失败的 webhook 请求实现重试以处理瞬态错误。 - 记录 webhook 事件以进行调试和监控。 - 使用安全的 HTTPS 端点接收 webhook。 - 设置速率限制以避免被多个 webhook 请求淹没。 :::tip 如果你想了解更多关于如何在 Next.js 中使用 webhooks 的信息,请查看[专门的博客文章](https://strapi.io/blog/how-to-create-an-ssg-static-site-generation-application-with-strapi-webhooks-and-nextjs)。 🌐 If you want to learn more about how to use webhooks with Next.js, please have a look at the [dedicated blog article](https://strapi.io/blog/how-to-create-an-ssg-static-site-generation-application-with-strapi-webhooks-and-nextjs). ::: # 命令行接口 Source: https://docs.strapi.io/cms/cli # 命令行接口 (CLI) {#command-line-interface-cli} 🌐 Command Line Interface (CLI) Strapi 带有功能齐全的命令行接口(CLI),使你可以在几秒钟内搭建和管理项目。CLI 可与 `yarn` 和 `npm` 包管理器一起使用。 🌐 Strapi comes with a full featured Command Line Interface (CLI) which lets you scaffold and manage your project in seconds. The CLI works with both the `yarn` and `npm` package managers. :::caution 像 `strapi admin:create-user` 这样的交互命令在使用 `npm` 时不会显示提示。请考虑使用 `yarn` 包管理器。 🌐 Interactive commands such as `strapi admin:create-user` don't display prompts with `npm`. Please consider using the `yarn` package manager. ::: :::note 建议仅在本地安装 Strapi,这需要在所有以下 `strapi` 命令前加上用于项目设置的包管理器(例如 `npm run strapi help` 或 `yarn strapi help`)或专用的 node 包执行器(例如 `npx strapi help`)。 🌐 It is recommended to install Strapi locally only, which requires prefixing all of the following `strapi` commands with the package manager used for the project setup (e.g `npm run strapi help` or `yarn strapi help`) or a dedicated node package executor (e.g. `npx strapi help`). 要使用 `npm` 传递选项,请使用以下语法:`npm run strapi -- --
### `compression` `compression` 中间件基于
### `cors` 这个安全中间件涉及跨源资源共享(CORS),并基于
示例:作为参数在函数中为cors中间件自定义配置 `origin` 可以接收一个符合此签名的函数作为参数 ```ts title="./config/middlewares.ts" // ... { name: 'strapi::cors', config: { origin: (ctx): string | string[] => { const origin = ctx.request.header.origin; if (origin === 'http://localhost:3000') { return origin; // The returns will be part of the Access-Control-Allow-Origin header } return ''; // Fail cors check } }, }, // ... ] ```
### `errors` 错误中间件处理代码抛出的[错误](/cms/error-handling.md)。根据错误的类型,它会为响应设置适当的HTTP状态。默认情况下,任何不应向终端用户暴露的错误都会导致500 HTTP响应。 🌐 The errors middleware handles [errors](/cms/error-handling.md) thrown by the code. Based on the type of error it sets the appropriate HTTP status to the response. By default, any error not supposed to be exposed to the end user will result in a 500 HTTP response. 中间件没有任何配置选项。 🌐 The middleware doesn't have any configuration options. ### `favicon` `favicon` 中间件用于提供网站图标,并基于
### `ip` `ip` 中间件是基于
### `logger` `logger` 中间件用于记录请求。 🌐 The `logger` middleware is used to log requests. 要为 `logger` 中间件定义自定义配置,请创建一个专用的配置文件(`./config/logger.js`)。它应导出一个对象,该对象必须是完整或部分的
### `poweredBy` `poweredBy` 中间件向响应头添加了一个 `X-Powered-By` 参数。它接受以下选项: 🌐 The `poweredBy` middleware adds a `X-Powered-By` parameter to the response header. It accepts the following options: | 选项 | 描述 | 类型 | 默认值 ||-------------|------------------------------------|----------|------------------------|| `poweredBy` | `X-Powered-By` 头的值 | `String` | `'Strapi '` |
详情 示例:poweredBy 中间件的自定义配置
### `query` `query` 中间件是基于
示例:针对长 REST 查询列表提高 arrayLimit 使用适合你最长括号编码列表的值(例如许多 `populate[n]` 条目)。根据你的需求和可接受的解析成本调整这个数字。 🌐 Use a value that fits your longest bracket-encoded lists (for example many `populate[n]` entries). Adjust the number based on your needs and acceptable parsing cost.
### `response-time` `response-time` 中间件启用响应头的 `X-Response-Time`(以毫秒为单位)。 🌐 The `response-time` middleware enables the `X-Response-Time` (in milliseconds) for the response header. 中间件没有任何配置选项。 🌐 The middleware doesn't have any configuration options. ### `public` `public` 中间件是一个静态文件服务中间件,基于
### `security` 安全中间件基于
### `session` `session` 中间件允许使用基于 cookie 的会话,基于 # 插件配置 Source: https://docs.strapi.io/cms/configurations/plugins # 插件配置 {#plugins-configuration} 🌐 Plugins configuration 插件配置存储在 `/config/plugins.js|ts` 中(参见 [项目结构](/cms/project-structure))。每个插件可以使用以下可用参数进行配置: 🌐 Plugin configurations are stored in `/config/plugins.js|ts` (see [project structure](/cms/project-structure)). Each plugin can be configured with the following available parameters: | 参数 | 描述 | 类型 || --- | --- | --- || `enabled` | 启用 (`true`) 或禁用 (`false`) 已安装的插件 | 布尔值 || `config`

_可选_ | 用于覆盖默认插件配置([在 strapi-server.js 中定义](/cms/plugins-development/server-configuration)) | 对象 || `resolve`
_可选,仅本地插件需要_ | 插件文件夹的路径 | 字符串 | :::note Configurations for core features and providers * Strapi 的一些核心功能历来是作为核心插件实现的。这就解释了为什么它们的配置仍然在 `/config/plugins` 文件中定义,尽管从技术上讲它们在 Strapi 5 中不再是插件。这包括: - 为支持媒体库的包的[上传配置](/cms/features/media-library#available-options), - 以及[用户与权限配置](/cms/features/users-permissions#code-based-configuration)。 详细的 [GraphQL 插件配置](/cms/plugins/graphql#code-based-configuration) 也记录在其专用插件页面中。 * 此外,媒体库和电子邮件功能的提供者配置也在 `/config/plugins` 中定义。它们的配置详见 [上传提供者配置](/cms/features/media-library#code-based-configuration) 和 [电子邮件提供者配置](/cms/features/email#providers)。 ::: **插件的基础自定义配置示例:** :::tip 如果不需要特定配置,插件也可以使用简写语法 `'plugin-name': true` 来声明。 🌐 If no specific configuration is required, a plugin can also be declared with the shorthand syntax `'plugin-name': true`. ::: # 服务器配置 Source: https://docs.strapi.io/cms/configurations/server # 服务器配置 {#server-configuration} 🌐 Server configuration `/config/server.js` 文件用于定义 Strapi 应用的服务器配置。 🌐 The `/config/server.js` file is used to define the server configuration for a Strapi application. :::caution 对 `server.js` 文件的更改需要重建管理面板。保存修改后的文件后,在终端中运行 `yarn build` 或 `npm run build` 以实现更改。 🌐 Changes to the `server.js` file require rebuilding the admin panel. After saving the modified file run either `yarn build` or `npm run build` in the terminal to implement the changes. ::: ## 可用选项 {#available-options} 🌐 Available options `./config/server.js` 文件可以包含以下参数: 🌐 The `./config/server.js` file can include the following parameters: | 参数 | 描述 | 类型 | 默认 | | --- | --- | --- | --- | | `host`

❗️ _必填_ | 主机名 | 字符串 | `localhost` | | `port`

❗️ _必填_ | 服务器应运行的端口。 | 整数 | `1337` | | `app.keys`

❗️ _必填_ | 声明会话密钥(基于 # TypeScript 配置 Source: https://docs.strapi.io/cms/configurations/typescript # TypeScript 配置 {#typescript-configuration} 🌐 TypeScript configuration [TypeScript](/cms/typescript) 支持的 Strapi 项目具有特定的项目结构,并通过 [`tsconfig.json` 文件](#project-structure-and-typescript-specific-configuration-files) 处理 TypeScript 项目配置。 Strapi 也有专门的 TypeScript 功能,这些功能在 [ `config/typescript.js|ts` 文件](#strapi-specific-configuration-for-typescript) 中进行配置。 🌐 Strapi also has dedicated TypeScript features that are configured [in the `config/typescript.js|ts` file](#strapi-specific-configuration-for-typescript). ## 项目结构和 TypeScript 特定的配置文件 {#project-structure-and-typescript-specific-configuration-files} 🌐 Project structure and TypeScript-specific configuration files 启用了 TypeScript 的 Strapi 应用具有特定的 [项目结构](/cms/project-structure),包括以下专用文件夹和配置文件: 🌐 TypeScript-enabled Strapi applications have a specific [project structure](/cms/project-structure) with the following dedicated folders and configuration files: | TypeScript 特定目录和文件 | 位置 | 目的 || --- | --- | --- || `./dist` 目录 | 应用根目录 | 添加用于编译项目 JavaScript 源代码的位置 || `build` 目录 | `./dist` | 包含已编译的管理面板 JavaScript 源代码。该目录在第一次 `yarn build` 或 `npm run build` 命令时创建 || `tsconfig.json` 文件 | 应用根目录 | 管理服务器的 TypeScript 编译 || `tsconfig.json` 文件 | `./src/admin/` | 管理管理面板的 TypeScript 编译 | ## TypeScript 的 Strapi 专用配置 {#strapi-specific-configuration-for-typescript} 🌐 Strapi-specific configuration for TypeScript :::caution 🚧 This feature is considered experimental. 这些设置被视为实验性的,可能会出现问题或破坏某些功能。 🌐 These settings are considered experimental and might have issues or break some features. ::: Strapi 生成的类型是基于用户项目结构的。一旦类型定义被导出到其专用文件中,Strapi 会读取这些类型定义以相应地调整自动补齐结果。 🌐 Types generated by Strapi are based on the user project structure. Once the type definitions are emitted into their dedicated files, Strapi reads the type definitions to adapt the autocompletion results accordingly. 为了避免每次服务器重启时都必须[手动生成类型](/cms/typescript/development#generate-typings-for-content-types-schemas),可以添加一个可选的 `config/typescript.js|ts` 配置文件,目前该文件仅接受一个参数: 🌐 To avoid having to [manually generate types](/cms/typescript/development#generate-typings-for-content-types-schemas) every time the server restarts, an optional `config/typescript.js|ts` configuration file can be added, which currently accepts only one parameter: | 参数 | 描述 | 类型 | 默认值 || --- | --- | --- | --- || `autogenerate` | 在服务器重启时启用或禁用自动类型生成 | `Boolean` | `false` | **示例:** # 自定义 Source: https://docs.strapi.io/cms/customization # 自定义 {#customization} 🌐 Customization Strapi 包括 2 个主要组件: 🌐 Strapi includes 2 main components: - Strapi 的后端部分是一个 **服务器**,它接收请求并处理这些请求,以返回通过内容类型构建器和内容管理器构建和保存的数据。后端服务器在 [后端自定义简介](/cms/backend-customization) 中有更详细的描述。大部分后端服务器的部分都可以自定义。 - Strapi 的前端、面向用户的部分称为 **管理面板**。管理面板是图形用户界面 (GUI),用于构建内容结构、创建和管理内容,以及执行可以通过内置或第三方插件管理的各种其他操作。管理面板的某些部分可以自定义。 从更大的角度来看,Strapi 在典型的、通用的设置中是这样集成的:Strapi 包含两个部分,一个后端服务器和一个管理面板,并与一个数据库(存储数据)以及一个显示数据的外部前端应用进行交互。Strapi 的这两个部分在一定程度上都可以定制。 🌐 From a bigger picture, this is how Strapi integrates in a typical, generic setup: Strapi includes 2 parts, a back-end server and an admin panel, and interact with a database (which stores data) and an external, front-end application that displays your data. Both parts of Strapi can be customized to some extent. :::info 自定义数据库或外部前端应用超出了本文档部分的范围。 🌐 Customizing the database or the external, front-end application are outside of the scope of the present documentation section. - 你可以通过阅读安装文档了解更多关于在 Strapi 中使用数据库的信息,安装文档列出了[支持的数据库](/cms/installation/cli#preparing-the-installation),以及配置文档,后者描述了如何将[数据库配置](/cms/configurations/database)到你的项目中。 - 你可以通过阅读 Strapi 的 了解更多关于外部前端应用如何与 Strapi 交互的信息。 ::: # 数据库迁移 Source: https://docs.strapi.io/cms/database-migrations # 数据库迁移 {#database-migrations} 🌐 Database migrations 数据库迁移用于对数据库运行一次性查询,通常是在升级 Strapi 应用时修改表结构或数据。这些迁移会在应用启动时自动运行,并且在 Strapi 在启动时执行的自动模式迁移之前执行。 🌐 Database migrations exist to run one-time queries against the database, typically to modify the tables structure or the data when upgrading the Strapi application. These migrations are run automatically when the application starts and are executed before the automated schema migrations that Strapi also performs on boot. :::callout 🚧 Experimental feature 数据库迁移是实验性的。此功能仍在开发中,将继续更新和改进。在此期间,欢迎随时在 此外,如果你想在使用 TypeScript 迁移的同时继续使用现有的 JavaScript 迁移,可以在你的 `tsconfig.json` 文件的编译器选项中设置 `allowJs: true`,如[数据库配置文档](/cms/configurations/database#settings-configuration-object)中所述。 🌐 Additionally, if you want to continue using existing JavaScript migrations alongside TypeScript migrations, you can set `allowJs: true` in your `tsconfig.json` file's compiler options, as mentioned in the [database configuration documentation](/cms/configurations/database#settings-configuration-object). # 数据库事务 Source: https://docs.strapi.io/cms/database-transactions # 数据库事务 {#database-transactions} 🌐 Database transactions :::caution 这是一个实验性功能,可能会在未来版本中发生变化。 🌐 This is an experimental feature and is subject to change in future versions. ::: Strapi 5 提供一个 API 来将一组操作封装在一个事务中,以确保数据的完整性。 🌐 Strapi 5 provide an API to wrap a set of operations in a transaction that ensures the integrity of data. 事务是一组作为单一单元一起执行的操作。如果其中任何操作失败,整个事务将失败,数据会回滚到之前的状态。如果所有操作都成功,事务将提交,数据将永久保存到数据库中。 🌐 Transactions are a set of operations that are executed together as a single unit. If any of the operations fail, the entire transaction fails and the data is rolled back to its previous state. If all operations succeed, the transaction is committed and the data is permanently saved to the database. ## 使用 {#usage} 🌐 Usage 事务通过将处理函数传入 `strapi.db.transaction` 来处理: 🌐 Transactions are handled by passing a handler function into `strapi.db.transaction`: ```js await strapi.db.transaction(async ({ trx, rollback, commit, onCommit, onRollback }) => { // It will implicitly use the transaction await strapi.entityService.create(); await strapi.entityService.create(); }); ``` 在事务处理程序执行后,如果所有操作都成功,则事务会被提交。如果任何操作抛出异常,事务将被回滚,数据会恢复到之前的状态。 🌐 After the transaction handler is executed, the transaction is committed if all operations succeed. If any of the operations throws, the transaction is rolled back and the data is restored to its previous state. :::note 在事务块中执行的每个 `strapi.entityService` 或 `strapi.db.query` 操作将隐式使用该事务。 🌐 Every `strapi.entityService` or `strapi.db.query` operation performed in a transaction block will implicitly use the transaction. ::: ### 事务处理器属性 {#transaction-handler-properties} 🌐 Transaction handler properties 处理程序函数接收具有以下属性的对象: 🌐 The handler function receives an object with the following properties: | 属性 | 描述 || --- | --- || `trx` | 事务对象。它可以用来在事务中执行 knex 查询。 || `commit` | 提交事务的函数。 || `rollback` | 回滚事务的函数。 || `onCommit` | 注册一个在事务提交后执行的回调函数的函数。 || `onRollback` | 注册一个在事务回滚后执行的回调函数的函数。 | ### 嵌套事务 {#nested-transactions} 🌐 Nested transactions 事务可以嵌套。当事务嵌套时,内层事务会在外层事务提交或回滚时被提交或回滚。 🌐 Transactions can be nested. When a transaction is nested, the inner transaction is committed or rolled back when the outer transaction is committed or rolled back. ```js await strapi.db.transaction(async () => { // It will implicitly use the transaction await strapi.entityService.create(); // Nested transactions will implicitly use the outer transaction await strapi.db.transaction(async ({}) => { await strapi.entityService.create(); }); }); ``` ### 在提交时和在回滚时 {#oncommit-and-onrollback} 🌐 onCommit and onRollback `onCommit` 和 `onRollback` 钩子可以用来在事务提交或回滚后执行代码。 🌐 The `onCommit` and `onRollback` hooks can be used to execute code after the transaction is committed or rolled back. ```js await strapi.db.transaction(async ({ onCommit, onRollback }) => { // It will implicitly use the transaction await strapi.entityService.create(); await strapi.entityService.create(); onCommit(() => { // This will be executed after the transaction is committed }); onRollback(() => { // This will be executed after the transaction is rolled back }); }); ``` ### 使用 knex 查询 {#using-knex-queries} 🌐 Using knex queries 事务也可以与 knex 查询一起使用,但在这些情况下必须显式调用 `.transacting(trx)`。 🌐 Transactions can also be used with knex queries, but in those cases `.transacting(trx)` must be explicitly called. ```js await strapi.db.transaction(async ({ trx, rollback, commit }) => { await knex('users').where('id', 1).update({ name: 'foo' }).transacting(trx); }); ``` ## 何时使用事务 {#when-to-use-transactions} 🌐 When to use transactions 在需要多次操作一起执行并且它们的执行相互依赖的情况下,应使用事务。例如,在创建新用户时,应该在数据库中创建用户,并向用户发送欢迎邮件。如果邮件发送失败,则不应在数据库中创建用户。 🌐 Transactions should be used in cases where multiple operations should be executed together and their execution is dependent on each other. For example, when creating a new user, the user should be created in the database and a welcome email should be sent to the user. If the email fails to send, the user should not be created in the database. ## 何时不使用事务 {#when-not-to-use-transactions} 🌐 When not to use transactions 事务不应用于不相互依赖的操作,因为它可能导致性能损失。 🌐 Transactions should not be used for operations that are not dependent on each other since it can result in performance penalties. ## 事务的潜在问题 {#potential-problems-of-transactions} 🌐 Potential problems of transactions 在事务内执行多个操作可能会导致锁定,这可能会阻止其他进程执行事务,直到原始事务完成。 🌐 Performing multiple operations within a transaction can lead to locking, which can block the execution of transactions from other processes until the original transaction is complete. 此外,如果事务未正确提交或回滚,则可能会停滞。 🌐 Furthermore, transactions can stall if they are not committed or rolled back appropriately. 例如,如果一个事务被打开,但你的代码中有一条路径没有关闭它,事务将会无限期地保持打开状态,并可能导致不稳定,直到你的服务器被重启并且连接被强制关闭。这些问题可能很难调试,因此在必要的情况下使用事务时要谨慎。 🌐 For example, if a transaction is opened but there is a path in your code that does not close it, the transaction will be left open indefinitely and could cause instability until your server is restarted and the connection is forced to close. These issues can be difficult to debug, so use transactions with care in the cases they are necessary. # 部署 Source: https://docs.strapi.io/cms/deployment # 部署 {#deployment} 🌐 Deployment Strapi 为你的项目或应用提供了多种部署选项。你的 Strapi 应用可以部署在传统托管服务器上,或你偏好的托管提供商上。 🌐 Strapi provides many deployment options for your project or application. Your Strapi applications can be deployed on traditional hosting servers or your preferred hosting provider. 以下文档介绍了如何使用几个常见的托管选项准备 Strapi 以进行部署的基础知识。 🌐 The following documentation covers the basics of how to prepare Strapi for deployment on with several common hosting options. :::strapi Strapi Cloud 你可以使用 [Strapi Cloud](/cloud/intro) 快速部署和托管你的项目。 🌐 You can use [Strapi Cloud](/cloud/intro) to quickly deploy and host your project. ::: :::tip 如果你已经使用内容类型构建器创建了内容结构,并通过内容管理器向本地(开发)Strapi 实例添加了一些数据,你可以利用[数据管理系统](/cms/features/data-management)将数据从一个 Strapi 实例传输到另一个实例。 🌐 If you already created a content structure with the Content-Type Builder and added some data through the Content Manager to your local (development) Strapi instance, you can leverage the [data management system](/cms/features/data-management) to transfer data from a Strapi instance to another one. 另一种可能的工作流程是首先在本地创建内容结构,将项目推送到基于 git 的存储库,将更改部署到生产环境,然后再将内容添加到生产实例。 🌐 Another possible workflow is to first create the content structure locally, push your project to a git-based repository, deploy the changes to production, and only then add content to the production instance. ::: :::caution 对于自托管的 Kubernetes 部署,我们建议使用 **npm** 而不是 **pnpm**。`pnpm` 对依赖的激进提升可能会破坏本地模块,例如 `mysql2`——你的应用可能依赖它们。`npm` 更平坦、更可预测的 `node_modules` 布局有助于确保本地包正确加载。 🌐 For self-hosted Kubernetes deployments, we recommend using **npm** rather than **pnpm**. `pnpm` aggressive hoisting of dependencies can break native modules, such as `mysql2`— that your application may rely on. `npm` flatter, more predictable `node_modules` layout helps ensure native packages load correctly. ::: ## 一般指南 {#general-guidelines} 🌐 General guidelines ### 硬件和软件要求 {#hardware-and-software-requirements} 🌐 Hardware and software requirements 为了为 Strapi 提供尽可能最佳的环境,以下要求适用于开发(本地)以及登台和生产工作流程。 🌐 To provide the best possible environment for Strapi the following requirements apply to development (local) and staging and production workflows. 使用 `production` 设置运行服务器: 🌐 Run the server with the `production` settings: :::caution 我们强烈推荐使用 来管理你的流程。 ::: 如果你需要一个 server.js 文件来运行 `node server.js` 而不是 `npm run start`,那么请创建一个 `./server.js` 文件,如下所示: 🌐 If you need a server.js file to be able to run `node server.js` instead of `npm run start` then create a `./server.js` file as follows: ```js title="path: ./server.js" const strapi = require('@strapi/strapi'); strapi.createStrapi(/* {...} */).start(); ``` :::caution 如果你正在开发一个基于 `TypeScript` 的项目,必须提供 `distDir` 选项来启动服务器。 欲了解更多信息,请查阅 [TypeScript 文档](/cms/typescript/development#use-the-createstrapi-factory)。 🌐 If you are developing a `TypeScript`-based project you must provide the `distDir` option to start the server. For more information, consult the [TypeScript documentation](/cms/typescript/development#use-the-createstrapi-factory). ::: :::tip Health check endpoint Strapi 在 `/_health` 提供了一个轻量级的健康检查路径,用于运行时间监控和负载均衡器。当服务器准备就绪时,它会返回一个 HTTP `204 No Content` 状态和一个 `strapi: You are so French!` 头值,你可以使用它来确认应用可访问。 🌐 Strapi exposes a lightweight health check route at `/_health` for uptime monitors and load balancers. When the server is ready, it responds with an HTTP `204 No Content` status and a `strapi: You are so French!` header value, which you can use to confirm the application is reachable. ::: ### 高级配置 {#advanced-configurations} 🌐 Advanced configurations 如果你想将管理界面托管在不同于 API 的服务器上,[请查看此专门部分](/cms/configurations/admin-panel#deploy-on-different-servers)。 🌐 If you want to host the administration on another server than the API, [please take a look at this dedicated section](/cms/configurations/admin-panel#deploy-on-different-servers). ## 附加资源 {#additional-resources} 🌐 Additional resources :::prerequisites * 你的 Strapi 项目已[创建](/cms/installation),其代码托管在 GitHub 上。 * 你已经阅读了[一般部署指南](/cms/deployment#general-guidelines)。 ::: Strapi 网站的 包含有关如何将 Strapi 与许多资源集成的信息,包括如何在以下第三方平台上部署 Strapi:
此外,社区维护的关于其他提供商的指南可在 获得。这包括以下指南:
以下外部指南(非 Strapi 官方维护)可能也有助于在各种环境中部署 Strapi: 🌐 The following external guide(s), not officially maintained by Strapi, might also help deploy Strapi on various environments: :::strapi Multi-tenancy 如果你在寻找多租户选项,Strapi 博客有一个 。 ::: # 错误处理 Source: https://docs.strapi.io/cms/error-handling # 错误处理 {#error-handling} 🌐 Error handling Strapi 本身就以标准格式处理错误。 🌐 Strapi is natively handling errors with a standard format. 错误处理有 2 个用例: 🌐 There are 2 use cases for error handling: - 作为通过 [REST](/cms/api/rest) 或 [GraphQL](/cms/api/graphql) API 查询内容的开发者,你可能会在请求响应中 [收到错误](#receiving-errors)。 - 作为开发者在定制 Strapi 应用的后端时,你可以使用控制器和服务来[抛出错误](#throwing-errors)。 ## 收到错误 {#receiving-errors} 🌐 Receiving errors 错误包含在响应对象中,使用 `error` 键,并包括诸如 HTTP 状态码、错误名称及附加信息等信息。 🌐 Errors are included in the response object with the `error` key and include information such as the HTTP status code, the name of the error, and additional information. ### REST 错误 {#rest-errors} 🌐 REST errors REST API 抛出的错误包含在具有以下格式的[响应](/cms/api/rest#requests)中: 🌐 Errors thrown by the REST API are included in the [response](/cms/api/rest#requests) that has the following format: ```json { "data": null, "error": { "status": "", // HTTP status "name": "", // Strapi error name ('ApplicationError' or 'ValidationError') "message": "", // A human readable error message "details": { // error info specific to the error type } } } ``` ### GraphQL 错误 {#graphql-errors} 🌐 GraphQL errors GraphQL API 抛出的错误包含在具有以下格式的响应中: 🌐 Errors thrown by the GraphQL API are included in the response that has the following format: ```json { "errors": [ { "message": "", // A human reable error message "extensions": { "error": { "name": "", // Strapi error name ('ApplicationError' or 'ValidationError'), "message": "", // A human reable error message (same one as above); "details": {}, // Error info specific to the error type }, "code": "" // GraphQL error code (ex: BAD_USER_INPUT) } } ], "data": { "graphQLQueryName": null } } ``` ## 抛出错误 {#throwing-errors} 🌐 Throwing errors
### 控制器和中间件 {#controllers-and-middlewares} 🌐 Controllers and middlewares 在使用 Strapi 开发任何自定义逻辑时,推荐的抛出错误的方式是让 [controller](/cms/backend-customization/controllers) 或 [middleware](/cms/backend-customization/middlewares) 返回正确的状态和主体。 🌐 The recommended way to throw errors when developing any custom logic with Strapi is to have the [controller](/cms/backend-customization/controllers) or [middleware](/cms/backend-customization/middlewares) respond with the correct status and body. 这可以通过在上下文上调用错误函数来完成(即 `ctx`)。可用的错误函数列在 ### 服务和模型生命周期 {#services-and-models-lifecycles} 🌐 Services and models lifecycles 一旦你在比控制器或中间件更深的层次工作,就有专门的错误类可以用来抛出错误。这些类是对 #### 示例:在模型生命周期中抛出错误** {#example-throwing-an-error-in-a-model-lifecycle} 🌐 Example: Throwing an error in a model lifecycle** 此示例展示了如何构建一个[自定义模型生命周期](/cms/backend-customization/models#lifecycle-hooks)并能够抛出一个错误,该错误会停止请求并将适当的错误信息返回给管理面板。通常你应该只在 `beforeX` 生命周期中抛出错误,而不是在 `afterX` 生命周期中抛出。 🌐 This example shows building a [custom model lifecycle](/cms/backend-customization/models#lifecycle-hooks) and being able to throw an error that stops the request and will return proper error messages to the admin panel. Generally you should only throw an error in `beforeX` lifecycles, not `afterX` lifecycles. ### 政策 {#policies} 🌐 Policies [策略](/cms/backend-customization/policies) 是一种特殊类型的中间件,在控制器执行之前运行。它们用于检查用户是否被允许执行该操作。如果用户不被允许执行该操作并且使用了 `return false`,则会抛出通用错误。作为替代,你可以使用从 Strapi `ForbiddenError` 类、`ApplicationError` 类派生的嵌套类扩展来抛出自定义错误消息(请参阅 [默认错误类](#default-error-classes) 了解这两个类),最后还可以使用 ### 默认错误类 {#default-error-classes} 🌐 Default error classes 默认的错误类可以从 `@strapi/utils` 包中获得,并可以在你的代码中导入和使用。任何默认的错误类都可以被扩展以创建自定义错误类。然后,自定义错误类可以在你的代码中使用来抛出错误。 🌐 The default error classes are available from the `@strapi/utils` package and can be imported and used in your code. Any of the default error classes can be extended to create a custom error class. The custom error class can then be used in your code to throw errors. # 管理面板 Source: https://docs.strapi.io/cms/features/admin-panel # 管理面板 {#administration-panel} 🌐 Administration panel 管理面板是你 Strapi 应用的后台。从管理面板,你将能够管理内容类型并编写实际内容,还可以管理用户,包括你的 Strapi 应用的管理员和终端用户。 🌐 The admin panel is the back office of your Strapi application. From the admin panel, you will be able to manage content-types and write their actual content, but also manage users, both administrators and end users of your Strapi application. ### 修改个人资料信息(名称、电子邮件、用户名) {#modifying-profile-information-name-email-username} 🌐 Modifying profile information (name, email, username) 1. 进入你个人资料的*个人资料*部分。 2. 填写以下选项: | 个人资料与经验 | 说明 || --- | --- || 名字 | 在文本框中填写你的名字。 || 姓氏 | 在文本框中填写你的姓氏。 || 电子邮件 | 在文本框中填写完整的电子邮件地址。 || 用户名 | (可选)在文本框中填写用户名。 | 3. 点击 **保存** 按钮。 ### 更改账户密码 {#changing-account-password} 🌐 Changing account password 1. 转到个人资料的*更改密码*部分。 2. 填写以下选项: | 密码修改 | 操作说明 || --- | --- || 当前密码 | 在文本框中输入你当前的密码。 || 密码 | 在文本框中输入新密码。 || 确认密码 | 在文本框中再次输入相同的新密码。 | 3. 点击 **保存** 按钮。 :::tip 你可以点击 图标以显示密码。 ::: ### 选择界面语言 {#choosing-interface-language} 🌐 Choosing interface language 在你个人资料的*经验*部分,使用*界面语言*下拉菜单选择你偏好的语言。 🌐 In the *Experience* section of your profile, select your preferred language using the *Interface language* dropdown. :::note 请记住,选择界面语言只适用于你在管理面板上的账户。同一应用管理面板的其他用户可以使用不同的语言。 🌐 Keep in mind that choosing an interface language only applies to your account on the admin panel. Other users of the same application's admin panel can use a different language. ::: ### 选择界面模式(明亮,黑暗) {#choosing-interface-mode-light-dark} 🌐 Choosing interface mode (light, dark) 默认情况下,所选择的界面模式是基于你的浏览器模式的。但是,你可以在个人资料的*体验*部分,通过*界面模式*下拉菜单手动选择浅色模式或夜间模式。 🌐 By default, the chosen interface mode is based on your browser's mode. You can however, in the *Experience* section of your profile, manually choose either the Light Mode or Dark Mode using the *Interface mode* dropdown. :::note 请记住,选择界面模式仅适用于管理面板上的账户。 🌐 Keep in mind that choosing an interface mode only applies to your account on the admin panel. ::: ### 重置导览 {#resetting-guided-tour} 🌐 Resetting guided tour 在你的个人资料的*导览*部分,你可以点击**重置导览**按钮来重置可在管理面板主页中使用的导览。如果你之前关闭了导览,这将允许你再次查看管理面板的导览,并重新跟随其各个步骤。 🌐 In the *Guided tour* section of your profile, you can click the **Reset guided tour** button to reset the guided tour which is available in the homepage of the admin panel. It allows you to see again the guided tour of the admin panel if you closed it beforehand, and to follow again its various steps. ### 自定义徽标 {#customizing-the-logo} 🌐 Customizing the logo **配置管理员面板的路径:** *设置 > 全局设置 > 概览* 可以修改 Strapi 应用主导航和身份验证页面中显示的默认 Strapi 徽标。 🌐 The default Strapi logos, displayed in the main navigation of a Strapi application and the authentication pages, can be modified. 1. 点击 *菜单标志* 或 *认证标志* 的上传区域。 2. 上传你选择的徽标,可以通过浏览文件、将文件拖放到右侧区域,或使用 URL。徽标尺寸不应超过 750x750 像素。 3. 在上传窗口中点击 **上传徽标** 按钮。 4. 点击右上角的**保存**按钮。 上传后,新徽标可以被替换为另一个徽标 ,或重置 为默认的 Strapi 徽标或配置文件中设置的徽标。 :::note 两种徽标也可以通过 Strapi 应用的配置文件以编程方式进行自定义(参见 [管理面板自定义](/cms/admin-panel-customization/logos))。但是,通过管理面板上传的徽标会覆盖通过配置文件设置的任何徽标。 🌐 Both logos can also be customized programmatically via the Strapi application's configuration files (see [Admin panel customization](/cms/admin-panel-customization/logos)). However, the logos uploaded via the admin panel supersedes any logo set through the configuration files. ::: ## 使用 {#usage} 🌐 Usage :::caution 为了访问管理面板,你的 Strapi 应用必须已启动,并且你必须知道其管理面板的 URL(例如 `api.example.com/admin`)。 🌐 In order to access the admin panel, your Strapi application must be launched, and you must be aware of the URL to its admin panel (e.g. `api.example.com/admin`). ::: 要访问管理面板: 🌐 To access the admin panel: 1. 转至 Strapi 应用管理面板的 URL。 2. 输入你的凭据以登录。 3. 点击 **登录** 按钮。你应该会被重定向到管理面板的主页。 :::note 如果你更喜欢或需要通过 SSO 提供商登录,请参阅 [单点登录文档](/cms/features/sso)。 🌐 If you prefer or are required to log in via an SSO provider, please refer to the [Single Sign-On documentation](/cms/features/sso). ::: # API 令牌 Source: https://docs.strapi.io/cms/features/api-tokens # API 令牌 {#api-tokens} 🌐 API Tokens API 令牌允许用户对 REST 和 GraphQL API 查询进行身份验证(参见 [API 介绍](/cms/api/content-api))。 🌐 API tokens allow users to authenticate REST and GraphQL API queries (see [APIs introduction](/cms/api/content-api)). :::caution Security 公共访问偏向使用只读令牌,将服务器令牌的权限限制在仅所需范围内,定期更换长期有效的令牌,并将它们存储在秘密管理器中。切勿在客户端代码中暴露管理员令牌。 🌐 Prefer read‑only tokens for public access, scope server tokens to only what you need, rotate long‑lived tokens, and store them in a secrets manager. Never expose admin tokens in client‑side code. ::: 此密钥用于加密和解密令牌值。没有此密钥,令牌仍然可以使用,但在初次显示后将无法查看。新的 Strapi 项目将自动生成此密钥。 🌐 This key is used to encrypt and decrypt token values. Without this key, tokens remain usable, but will not be viewable after initial display. New Strapi projects will have this key automatically generated. ## 使用 {#usage} 🌐 Usage 使用 API 令牌可以以经过身份验证的用户身份在 [REST API](/cms/api/rest) 或 [GraphQL API](/cms/api/graphql) 端点上执行请求。 🌐 Using API tokens allows executing a request on [REST API](/cms/api/rest) or [GraphQL API](/cms/api/graphql) endpoints as an authenticated user. API 令牌有助于授予人员或应用访问权限,而无需管理用户账户或更改用户和权限插件中的任何内容。 🌐 API tokens can be helpful to give access to people or applications without managing a user account or changing anything in the Users & Permissions plugin. 在向 Strapi 的 REST API 执行请求时,API 令牌应以以下语法添加到请求的 `Authorization` 头中:`bearer your-api-token`。 🌐 When performing a request to Strapi's REST API, the API token should be added to the request's `Authorization` header with the following syntax: `bearer your-api-token`. :::note 只读 API 令牌只能访问 `find` 和 `findOne` 功能。 🌐 Read-only API tokens can only access the `find` and `findOne` functions. ::: # 审计日志 Source: https://docs.strapi.io/cms/features/audit-logs # 审计日志 审计日志功能提供可搜索和可过滤的显示,显示 Strapi 应用用户执行的所有活动。 🌐 The Audit Logs feature provides a searchable and filterable display of all activities performed by users of the Strapi application. ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** 设置 > 管理面板 - 审计日志 审计日志功能记录以下事件: 🌐 The Audit Logs feature logs the following events: | 事件 | 操作 || --- | --- || 内容类型 | `create`, `update`, `delete` || 条目(草稿/发布) | `create`, `update`, `delete`, `publish`, `unpublish` || 媒体 | `create`, `update`, `delete` || 登录 / 注销 | `success`, `fail` || 角色 / 权限 | `create`, `update`, `delete` || 用户 | `create`, `update`, `delete` | 对于每个日志项,将显示以下信息: 🌐 For each log item, the following information is displayed: - 操作:用户执行的操作类型(例如 `create` 或 `update`)。 - 日期:操作的日期和时间。 - 用户:执行操作的用户。 - 详情:显示一个模态窗口,提供关于该操作的更多详情(例如用户 IP 地址、请求体或响应体)。 ### 过滤日志 {#filtering-logs} 🌐 Filtering logs 默认情况下,所有日志按时间倒序显示。你可以按以下方式筛选日志: 🌐 By default, all logs are displayed in reverse chronological order. You can filter the logs by: - 操作:选择要过滤的操作类型(例如 `create` 或 `update`)。 - 用户:选择要筛选的用户。 - 日期:选择要筛选的日期(范围)和时间。 ### 正在访问日志详情 {#log-details} 🌐 Accessing log details 对于任何日志项,点击 图标即可访问一个包含该操作更多详细信息的模态窗口。在模态窗口中,*Payload* 部分以交互式 JSON 组件显示详细信息,使你可以展开和折叠 JSON 对象。 # 内容历史 Source: https://docs.strapi.io/cms/features/content-history # 内容历史 在 ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** 内容管理器
在内容类型的编辑视图中:点击 (右上角)然后 **内容历史**. ### 浏览内容历史 {#browsing-content-history} 🌐 Browsing Content History 使用内容历史记录,你可以通过以下方式浏览内容: 🌐 With Content History, you can browse your content through: - 左侧的主视图列出了右侧侧边栏中所选版本的字段及其内容。 - 右侧的侧边栏列出了可用版本的总数以及每个版本: - 创建版本的日期和时间, - 创建它的用户, - 以及其状态是草稿、已修改还是已发布(有关文档状态的更多信息,请参见 [草稿与发布](/cms/features/draft-and-publish))。 :::note 内容历史的主要视图清楚地说明了某个字段在内容类型的其他版本中是不存在的、已删除的还是已重命名的。对于所选版本未知的字段,将在其他字段下方以“_未知字段_”标题显示。 🌐 The main view of Content History clearly states whether a field was inexistent, deleted, or renamed in other versions of the content-type. Fields that are unknown for the selected version will be displayed under an _Unknown fields_ heading below the other fields. ::: ### 恢复先前的版本 {#restoring-a-previous-version} 🌐 Restoring a previous version 你可以选择恢复文档的先前版本。恢复版本时,该版本的内容将覆盖当前草稿版本的内容。文档状态将变为“已修改”,然后你就可以随时发布该内容(参见[发布草稿](/cms/features/draft-and-publish#publishing-a-draft))。 🌐 You can choose to restore a previous version of a document. When restoring a version, the content of this version will override the content of the current draft version. The document switches to the Modified status and you will then be able to publish the content whenever you want (see [Publishing a draft](/cms/features/draft-and-publish#publishing-a-draft)). 1. 浏览内容历史记录并通过右侧的侧边栏选择一个版本。 2. 点击 **恢复** 按钮。 3. 在“确认”窗口中,点击**恢复**。 :::note 如果为内容类型启用了[国际化 (i18n)](/cms/features/internationalization) 功能,恢复具有唯一字段(即其内容在所有语言环境中相同的字段)的版本将会恢复该字段在所有语言环境中的内容。 🌐 If the [Internationalization (i18n)](/cms/features/internationalization) feature is enabled for the content-type, restoring a version with a unique field (i.e. a field whose content is the same for all locales) will restore the content of this field for all locales. ::: # 内容经理 Source: https://docs.strapi.io/cms/features/content-manager # 内容经理 {#content-manager} 🌐 Content Manager 从 ## 概览 {#overview} 🌐 Overview ### 配置编辑视图 {#edit-view-settings} 🌐 Configuring the edit view ## 使用 {#usage} 🌐 Usage
### 创建与撰写内容 {#creating--writing-content} 🌐 Creating & Writing content 在 Strapi 中,编写内容包括填写字段,这些字段用于包含特定内容(例如文本、数字、媒体等)。这些字段已经通过 [内容类型构建器](/cms/features/content-type-builder) 为集合或单一类型预先配置好。 🌐 In Strapi, writing content consists in filling up fields, which are meant to contain specific content (e.g. text, numbers, media, etc.). These fields were configured for the collection or single type beforehand, through the [Content-type Builder](/cms/features/content-type-builder). #### 动态区域 {#dynamic-zones} 🌐 Dynamic zones 动态区域是由组件组合而成的,而组件本身又由多个字段组成。编写动态区域的内容需要额外步骤以访问这些字段。 🌐 Dynamic zones are a combination of components, which themselves are composed of several fields. Writing the content of a dynamic zone requires additional steps in order to access the fields. :::tip - 并非所有条目都默认列出:可以通过点击 **加载更多** 按钮显示更多条目。此外,与其通过滚动列表选择条目,不如点击任何关联字段下拉列表并输入以搜索特定条目。 - 点击条目的名称以打开它。行为取决于在编辑视图中配置的**关联打开行为**设置:条目可以在模态窗口中打开(默认)、导航到其完整编辑页面,或在新的浏览器标签中打开。请参阅[配置编辑视图](#edit-view-settings)以更改此设置。 ::: :::note - 如果内容类型的关系字段启用了[草稿 & 发布功能](/cms/features/draft-and-publish),你会在下拉列表中看到条目名称旁边出现蓝色或绿色的点。这些点分别表示条目的状态,即草稿或已发布内容。 - 如果内容类型启用了[国际化 (i18n) 功能](/cms/features/internationalization),条目列表可能会受到限制或因语言环境而异。仅会列出可能被选作关联字段的相关条目。 ::: ### 删除内容 {#deleting-content} 🌐 Deleting content 你可以通过删除集合类型的任意条目或单一类型的默认条目来删除内容。 🌐 You can delete content by deleting any entry of a collection type, or the default entry of a single type. 1. 在条目的编辑视图中,点击界面右上角的 ,然后点击**删除文档**按钮。
如果内容类型启用了国际化,你还可以选择仅删除当前所选的语言版本,方法是点击**删除语言版本**按钮。 2. 在弹出的窗口中,点击 **确认** 按钮以确认删除。 :::tip 你可以通过在表格中条目记录的右侧点击 ,然后选择 **删除文档**按钮,从集合类型的列表视图中删除条目。
如果内容类型启用了[国际化](/cms/features/internationalization),**删除文档**会删除所有语言版本,而**删除语言版本**只会删除当前列出的语言版本。 # 内容类型构建器 Source: https://docs.strapi.io/cms/features/content-type-builder # 内容类型构建器 {#content-type-builder} 🌐 Content-type Builder 在 ## 概览 {#overview} 🌐 Overview 3. 在对话框中点击 **完成** 按钮。 4. 在内容类型构建器导航中点击**保存**按钮。 #### 字段 {#fields} 🌐 Fields 从列出内容类型字段的表格中,你可以: 🌐 From the table that lists the fields of your content-type, you can: - 点击 #### 富文本(块) {#rich-text-blocks} 富文本(块)字段显示一个带有实时渲染和各种选项的编辑器,用于管理富文本。此字段可用于较长的书面内容,甚至包括图片和代码。 🌐 The Rich Text (Blocks) field displays an editor with live rendering and various options to manage rich text. This field can be used for long written content, even including images and code. :::strapi React renderer 如果使用积木编辑器,我们建议你也使用 #### 日期 {#date} 日期字段可以显示日期(年、月、日)、时间(时、分、秒)或日期时间(年、月、日、时、分、秒)选择器。 🌐 The Date field can display a date (year, month, day), time (hour, minute, second) or datetime (year, month, day, hour, minute, and second) picker. #### 密码 {#img-width28-srcimgassetsiconsv5ctbpasswordsvg--password} 密码字段显示已加密的密码字段。 🌐 The Password field displays a password field that is encrypted. #### 媒体 {#media} 媒体字段允许从应用媒体库中上传的媒体文件中选择一个或多个媒体文件(例如图片、视频)。 🌐 The Media field allows to choose one or more media files (e.g. image, video) from those uploaded in the Media Library of the application. #### 关系 {#relation} Relation 字段允许与另一个内容类型建立关系,该内容类型必须是集合类型。 🌐 The Relation field allows to establish a relation with another content-type, that must be a collection type. 有 6 种不同类型的关系: 🌐 There are 6 different types of relations: - 一种方式:内容类型A *有一个* 内容类型B - 一对一:内容类型 A *有并属于一个* 内容类型 B - 一对多:内容类型 A *属于多个* 内容类型 B - 多对一:内容类型 B *拥有多个* 内容类型 A - 多对多:内容类型 A *拥有并属于多个* 内容类型 B - 多种方式:内容类型 A *有多种* 内容类型 B :::info Multi relations and single relations 至少有一方可以引用多个条目的关系称为多重关系。在内容类型构建器中,这包括一对多、多对一、多对多和多向关系。这些关系在内容管理器中显示为多选字段,并且从 REST、GraphQL 和文档服务 API 返回数组;而单一关系(一向和一对一关系)返回单个关联条目(有关更多信息,请参见 [使用 API 请求管理关系](/cms/api/rest/relations))。 🌐 Relations where at least one side can reference several entries are called multi relations. In the Content-type Builder, this includes one-to-many, many-to-one, many-to-many, and many-way relations. These relations appear as multi-select fields in the Content Manager and return arrays from the REST, GraphQL, and Document Service APIs; while single relations (one-way and one-to-one relations) return a single linked entry (see [Managing relations with API requests](/cms/api/rest/relations) for more information). ::: :::tip Modeling nested page hierarchies 要对可导航的页面树进行建模: 🌐 To model a navigable tree of pages: 1. 添加一个 `Page` 集合类型,并包含一个“Slug”(UID)字段,以及一个可选的“Order”(整数)字段来控制同级排序。 2. 从 `Page` 到 `Page` 创建一个关联字段,并选择 *多对一*,这样每个页面都可以设置它的“父页面”。Strapi 会自动提供反向的“子页面”关联。 3. 在读取数据时,递归地填充 `children` 以加载树。保持递归深度较小以避免响应过大。
示例 ```json title="Populate nested children for a page tree" { populate: { children: { fields: ['title', 'slug'], populate: { children: { fields: ['title', 'slug'], }, }, }, }, } ```
相同的填充模式适用于 GraphQL 或文档服务 API(参见 [理解填充指南](/cms/api/rest/guides/understanding-populate#populate-several-levels-deep-for-specific-relations))。 🌐 The same populate pattern works with GraphQL or the Document Service API (see [Understanding populate guide](/cms/api/rest/guides/understanding-populate#populate-several-levels-deep-for-specific-relations)). ::: #### 布尔 {#boolean} 布尔字段显示一个切换按钮来管理布尔值(例如是或否、1 或 0、True 或 False)。 🌐 The Boolean field displays a toggle button to manage boolean values (e.g. Yes or No, 1 or 0, True or False). #### JSON {#json} JSON 字段允许以 JSON 格式配置数据,以存储 JSON 对象或数组。 🌐 The JSON field allows to configure data in a JSON format, to store JSON objects or arrays. #### 电子邮件 {#email} 电子邮件字段显示带有格式验证的电子邮件地址字段,以确保电子邮件地址有效。 🌐 The Email field displays an email address field with format validation to ensure the email address is valid. #### 密码 {#password} 密码字段显示已加密的密码字段。 🌐 The Password field displays a password field that is encrypted. #### 枚举 {#enum} 枚举字段允许配置下拉列表中显示的值列表。 🌐 The Enumeration field allows to configure a list of values displayed in a drop-down list. :::caution 枚举值应始终在任何数字前有一个字母字符,否则在安装 GraphQL 插件时可能会导致服务器崩溃而不另行通知。 🌐 Enumeration values should always have an alphabetical character preceding any number as it could otherwise cause the server to crash without notice when the GraphQL plugin is installed. ::: #### UID {#uid} UID 字段显示设置唯一标识符的字段,可以选择基于相同内容类型的现有其他字段。 🌐 The UID field displays a field that sets a unique identifier, optionally based on an existing other field from the same content-type. :::tip UID 字段可用于根据 Attached 字段创建 slug。 🌐 The UID field can be used to create a slug based on the Attached field. ::: #### 富文本(Markdown) {#rich-text-markdown} 富文本(Markdown)字段显示一个带有基本格式选项的编辑器,用于管理以Markdown编写的富文本。此字段可用于较长的书面内容。 🌐 The Rich Text (Markdown) field displays an editor with basic formatting options to manage rich text written in Markdown. This field can be used for long written content. #### 组件 {#components} 组件是多个字段的组合。组件允许创建可重用的字段集合,这些集合可以快速添加到内容类型、动态区域,也可以嵌套到其他组件中。 🌐 Components are a combination of several fields. Components allow to create reusable sets of fields, that can be quickly added to content-types, dynamic zones but also nested into other components. 通过内容类型生成器配置组件时,可以: 🌐 When configuring a component through the Content-type Builder, it is possible to either: - 通过点击 *创建新组件* 来创建一个新组件(参见 [创建新组件](#new-component)), - 或者点击*使用现有组件*来使用已有的组件。 #### 动态区域 {#dynamiczones} 动态区域是可以添加到内容类型中的组件组合。它们允许灵活的内容结构,因为一旦进入内容管理器,管理员可以根据需要选择如何组合和重新排列动态区域的组件。 🌐 Dynamic zones are a combination of components that can be added to content-types. They allow a flexible content structure as once in the Content Manager, administrators have the choice of composing and rearranging the components of the dynamic zone how they want. 在配置动态区域的设置之后,其组件也必须进行配置。可以选择现有组件或创建一个新组件。 🌐 After configuring the settings of the dynamic zone, its components must be configured as well. It is possible to either choose an existing component or create a new one. :::caution 使用动态区域时,不同组件不能具有不同类型(或枚举字段、不同值)的相同字段名称。 🌐 When using dynamic zones, different components cannot have the same field name with different types (or with enumeration fields, different values). ::: #### 自定义字段 {#custom-fields} 🌐 Custom fields [自定义字段](/cms/features/custom-fields) 是通过向内容类型或组件添加新类型字段来扩展 Strapi 功能的一种方式。安装后(参见 [Marketplace](/cms/plugins/installing-plugins-via-marketplace) 文档),在为内容类型选择字段时,自定义字段会列在 _自定义_ 选项卡中。 每种自定义字段类型都可以有基本和高级设置。 列出可用的自定义字段,并为每个自定义字段提供专门的文档,包括具体设置。 ### 删除内容类型 {#deleting-content-types} 🌐 Deleting content-types 内容类型和组件可以通过内容类型构建器删除。删除内容类型会自动删除内容管理器中基于该内容类型的所有条目。组件的删除也是如此,它会自动从使用该组件的所有内容类型或条目中删除。 🌐 Content types and components can be deleted through the Content-type Builder. Deleting a content-type automatically deletes all entries from the Content Manager that were based on that content-type. The same goes for the deletion of a component, which is automatically deleted from every content-type or entry where it was used. 1. 在 内容类型构建器子导航中,点击要删除的内容类型或组件的名称。 2. 在所选内容类型或组件的编辑界面中,点击内容类型或组件名称右侧的 **编辑**按钮。 3. 在编辑窗口中,点击 **删除** 按钮。 4. 在确认窗口中,确认删除。 5. 在内容类型构建器子导航中点击 **保存** 按钮。 :::caution 删除内容类型只会删除通过内容类型构建器创建的内容,以及由此从你的 Strapi 应用的管理面板中可访问的内容。然而,基于该内容类型创建的所有数据仍会保留在数据库中。有关更多信息,请参阅相关 。 ::: # 自定义字段 Source: https://docs.strapi.io/cms/features/custom-fields # 自定义字段 {#custom-fields} 🌐 Custom Fields 自定义字段通过向内容类型和组件添加新类型的字段来扩展 Strapi 的功能。一旦通过插件创建或添加到 Strapi,自定义字段就可以像内置字段一样在内容类型构建器和内容管理器中使用。 🌐 Custom fields extend Strapi’s capabilities by adding new types of fields to content-types and components. Once created or added to Strapi via plugins, custom fields can be used in the Content-Type Builder and Content Manager just like built-in fields. ## 配置 {#configuration} 🌐 Configuration 现成的自定义字段可以在 [Marketplace](https://market.strapi.io/plugins?categories=Custom+fields) 找到。安装后,无需其他配置,即可开始使用它们(参见 [使用方法](#usage))。 🌐 Ready-made custom fields can be found on the [Marketplace](https://market.strapi.io/plugins?categories=Custom+fields). Once installed these, no other configuration is required, and you can start using them (see [usage](#usage)). 你也可以开发自己的自定义字段。 🌐 You can also develop your own custom field. ### 开发你自己的自定义字段 {#developing-your-own-custom-field} 🌐 Developing your own custom field 虽然推荐的添加自定义字段的方法是通过创建插件,但特定应用的自定义字段也可以在 `src/index` 和 `src/admin/app` 文件中找到的全局 `register` [函数](/cms/configurations/functions) 中注册。 🌐 Though the recommended way to add a custom field is through creating a plugin, app-specific custom fields can also be registered within the global `register` [function](/cms/configurations/functions) found in `src/index` and `src/admin/app` files. :::note Current limitations * 自定义字段只能使用插件在 Marketplace 上共享和分发。 * 自定义字段不能为 Strapi 添加新的数据类型,必须使用在 [模型属性](/cms/backend-customization/models#model-attributes) 文档中描述的现有内置 Strapi 数据类型。 * 你也无法修改现有的数据类型。 * Strapi 特有的特殊数据类型(例如关系、媒体、组件或动态区域数据类型)不能在自定义字段中使用。 ::: :::prerequisites 如果你没有使用 CLI 生成器生成插件代码,该自定义字段也可以直接在 `strapi-server.js` 文件中声明: 🌐 The custom field could also be declared directly within the `strapi-server.js` file if you didn't have the plugin code scaffolded by the CLI generator: #### 在管理面板中注册自定义字段 {#registering-a-custom-field-in-the-admin-panel} 🌐 Registering a custom field in the admin panel :::prerequisites ##### 组件 {#components} 🌐 Components `app.customFields.register()` 必须传递一个包含 `Input` React 组件的 `components` 对象,以在内容管理器的编辑视图中使用。 **示例:注册一个输入组件:** 在以下示例中,`color-picker` 插件是使用 CLI 生成器创建的(参见 [插件开发](/cms/plugins-development/developing-plugins.md)): 🌐 In the following example, the `color-picker` plugin was created using the CLI generator (see [plugins development](/cms/plugins-development/developing-plugins.md)):
传递给自定义字段 Input 组件的属性: | 属性 | 描述 | 类型 | | --- | --- | --- | | `attribute` | 带有自定义字段的属性对象的底层 Strapi 类型和选项 | `{ type: String, customField: String }` | | `description` | 在 [配置视图](/cms/features/content-manager#edit-view-settings) 中设置的字段描述 | :::tip 要详细了解提供给 customFields 的 props 以及它们如何使用,请查看 Strapi 代码库中的 :::tip Strapi 代码库提供了一个示例,说明如何描述设置对象:查看 文件中的 `base` 设置,以及 文件中的 `advanced` 设置。基础表单将设置项以内联方式列出,而高级表单则从 文件中获取设置项。 🌐 The Strapi codebase gives an example of how settings objects can be described: check the file for the `base` settings and the file for the `advanced` settings. The base form lists the settings items inline but the advanced form gets the items from an file. ::: ## 使用 {#usage} 🌐 Usage
### 在管理面板中 {#in-the-admin-panel} 🌐 In the admin panel 可以通过从 [Marketplace](/cms/plugins/installing-plugins-via-marketplace) 安装或创建自己的字段来向 Strapi 添加自定义字段。 🌐 Custom fields can be added to Strapi either by installing them from the [Marketplace](/cms/plugins/installing-plugins-via-marketplace) or by creating your own. 一旦添加到 Strapi,自定义字段可以添加到任何内容类型。选择内容类型的字段时,自定义字段会列在 _Custom_ 选项卡中。 🌐 Once added to Strapi, custom fields can be added to any content type. Custom fields are listed in the _Custom_ tab when selecting a field for a content-type. 每种自定义字段类型都可以有基本和高级设置。 列出可用的自定义字段,并为每个自定义字段提供专门的文档,包括具体设置。 ### 在代码中 {#in-the-code} 🌐 In the code 创建和使用后,自定义字段的定义就像模型架构中的任何其他属性一样。 🌐 Once created and used, custom fields are defined like any other attribute in the model's schema. 自定义字段在模型的[属性](/cms/backend-customization/models#model-attributes)中使用 `type: customField` 明确定义。 🌐 Custom fields are explicitly defined in the [attributes](/cms/backend-customization/models#model-attributes) of a model with `type: customField`. 与其他类型的模型定义方式相比,自定义字段的属性还具有以下特性: 🌐 As compared to how other types of models are defined, custom fields' attributes also show the following specificities: - 自定义字段具有 `customField` 属性。其值充当唯一标识符,用于指示应使用哪个已注册的自定义字段,并遵循以下两种格式之一: | 格式 | 来源 | |----------------------|------------------| | `plugin::plugin-name.field-name` | 自定义字段是通过插件创建的 | | `global::field-name` | 自定义字段特定于当前 Strapi 应用,并且是直接在 `register` [函数](/cms/configurations/functions) 中创建的 | - 自定义字段可以根据注册自定义字段时定义的内容拥有额外的参数(参见[服务器注册](#registering-a-custom-field-on-the-server)和[管理面板注册](#registering-a-custom-field-in-the-admin-panel))。 **示例:一个简单的 `color` 自定义字段模型定义:** ```json title="/src/api/[apiName]/[content-type-name]/content-types/schema.json" { // … "attributes": { "color": { // name of the custom field defined in the Content-Type Builder "type": "customField", "customField": "plugin::color-picker.color", "options": { "format": "hex" } } } // … } ``` # 数据管理 Source: https://docs.strapi.io/cms/features/data-management # 数据管理 {#data-management} 🌐 Data Management 数据管理功能可用于导入、导出或转移数据。数据管理仅基于命令行接口,但部分配置可以在管理面板中进行。 🌐 The Data Management feature can be used to import, export, or transfer data. Data Management is CLI-based only, but is partly configured in the admin panel. ## 配置 {#configuration} 🌐 Configuration 数据管理功能的一些配置选项在管理面板中可用,一些通过你的 Strapi 项目的代码处理。 🌐 Some configuration options for the Data Management feature are available in the admin panel, and some are handled via your Strapi project's code. ### 管理面板设置 {#admin-panel-settings} 🌐 Admin panel settings :::prerequisites `transfer.token.salt` 应该在 `config/admin` 配置文件中定义(参见 [基于代码的配置](#code-based-configuration))。 🌐 A `transfer.token.salt` should be defined in the `config/admin` configuration file (see [code-based configuration](#code-based-configuration)). ::: **配置此功能的路径:** ## 使用 {#usage} 🌐 Usage 数据管理系统仅基于命令行接口(CLI),这意味着任何导入、导出或传输命令都必须从终端执行。每个命令的详尽文档可以从以下页面获得: 🌐 The Data Management system is CLI-based only, meaning any import, export, or transfer command must be executed from the terminal. Exhaustive documentation for each command is accessible from the following pages: # 草稿与发布 Source: https://docs.strapi.io/cms/features/draft-and-publish # 草稿与发布 {#draft--publish} 🌐 Draft & Publish 草稿和发布功能允许管理内容的草稿。 🌐 The Draft & Publish feature allows to manage drafts for your content. 在 Strapi 的后端服务器上,文档服务 API 还可用于与本地化内容进行交互: 🌐 On the back-end server of Strapi, the Document Service API can also be used to interact with localized content: # 电子邮件 Source: https://docs.strapi.io/cms/features/email # 电子邮件 {#email} 🌐 Email 电子邮件功能使 Strapi 应用能够从服务器或外部提供商发送电子邮件。 🌐 The Email feature enables Strapi applications to send emails from a server or an external provider. ## 配置 {#configuration} 🌐 Configuration 电子邮件功能的大多数配置选项通过你的 Strapi 项目代码进行处理。管理面板提供了当前配置、连接状态和提供商功能的只读视图,并允许用户发送测试电子邮件。 🌐 Most configuration options for the Email feature are handled via your Strapi project's code. The admin panel provides a read-only view of the current configuration, connection status, and provider capabilities, and lets users send a test email. :::info Provider vs. host - 电子邮件提供商指的是 Strapi 用来发送电子邮件的包(例如官方提供商如 Sendgrid 或社区包如 `@strapi/provider-email-nodemailer`)。当 Strapi 调用它们时,提供商实现发送邮件的逻辑。 - 提供商主机(或服务器)是指提供商公开的连接详细信息(例如 SMTP 主机名、端口或 REST API 端点)。一些提供商将这些详细信息隐藏在 API 密钥后面,而另一些则要求你在配置中提供与主机相关的选项。 电子邮件功能仅处理外发投递。接收或解析传入的消息不在内置插件的范围内,必须通过你的电子邮件提供商的入站 Webhook 或自定义集成来实现。 🌐 The Email feature only handles outbound delivery. Receiving or parsing incoming messages is outside the scope of the built-in plugin and must be implemented with your email provider's inbound webhooks or a custom integration. ::: ### 管理面板设置 {#admin-panel-settings} 🌐 Admin panel settings **配置此功能的路径:** ##### 配置提供者 {#configuring-providers} 🌐 Configuring providers 新安装的提供程序已在 [“/config/plugins” 文件](/cms/configurations/plugins) 中启用并配置。如果该文件不存在,你必须创建它。 🌐 Newly installed providers are enabled and configured in [the `/config/plugins` file](/cms/configurations/plugins). If this file does not exist you must create it. :::info Specific email providers configurations - 每个提供商将拥有不同的配置设置。请查看该提供商在 [Marketplace](/cms/plugins/installing-plugins-via-marketplace) 或 :::note Notes * 在每个环境使用不同的提供者时,请在 `/config/env/${yourEnvironment}/plugins.js|ts` 中指定正确的配置(参见 [Environments](/cms/configurations/environment))。 * 一次只能激活一个电子邮件提供商。如果 Strapi 没有识别电子邮件提供商设置,请确认 `plugins.js|ts` 文件在正确的文件夹中。 * 在使用 Strapi 设置期间创建的两个电子邮件模板测试新的电子邮件提供商时,模板上的 _发件人邮箱_ 默认为 `no-reply@strapi.io`,需要根据你的电子邮件提供商进行更新,否则测试将失败(请参见 [本地配置模板](/cms/features/users-permissions#templating-emails))。 * 为了获得最佳的邮件送达率,请与你的电子邮件提供商配置 SPF/DKIM,并确保 `defaultFrom` 域与你在提供商处验证的域一致。 ::: ###### 每环境配置 {#per-environment-configuration} 🌐 Per-environment configuration 在配置你的提供者时,你可能希望根据 `NODE_ENV` 环境变量更改配置,或使用特定环境的凭据。 🌐 When configuring your provider you might want to change the configuration based on the `NODE_ENV` environment variable or use environment specific credentials. 你可以在 `/config/env/{env}/plugins.js|ts` 配置文件中设置特定配置,它将用于覆盖默认配置。 🌐 You can set a specific configuration in the `/config/env/{env}/plugins.js|ts` configuration file and it will be used to overwrite the default configuration. 有些提供商会暴露 SMTP 风格的连接详情,而不是(或除了)API 密钥。在 `providerOptions` 中添加这些值,以便 Strapi 可以访问提供商主机。例如,社区版 Nodemailer 提供商需要主机、端口和认证凭据: 🌐 Some providers expose SMTP-style connection details instead of (or in addition to) an API key. Add those values in `providerOptions` so Strapi can reach the provider host. For instance, the community Nodemailer provider expects the host, port, and authentication credentials: 如果你的提供商给你的是单个 URL 而不是主机和端口值,请在 `providerOptions` 中使用该 URL(例如 `https://api.eu.mailgun.net`),使用该包所期望的键。 🌐 If your provider gives you a single URL instead of host and port values, pass that URL (for example `https://api.eu.mailgun.net`) in `providerOptions` using the key the package expects. ##### 构建自定义提供程序 {#building-a-custom-provider} 🌐 Building a custom provider 要构建你自己的提供者,将其发布到 npm,或在你的项目中本地使用,请参阅专门的文档: 🌐 To build your own provider, publish it to npm, or use it locally in your project, see the dedicated documentation: ## 使用 {#usage} 🌐 Usage 电子邮件功能使用 Strapi 全局 API,这意味着它可以在 Strapi 应用的任何地方调用,无论是通过后台服务器本身的 [控制器或服务](#controller-service) 还是从管理面板,例如响应某个事件时(使用 [生命周期钩子](#lifecycle-hook))。 🌐 The Email feature uses the Strapi global API, meaning it can be called from anywhere inside a Strapi application, either from the back-end server itself through a [controller or service](#controller-service), or from the admin panel, for example in response to an event (using [lifecycle hooks](#lifecycle-hook)). ### 使用控制器或服务发送电子邮件 {#controller-service} 🌐 Sending emails with a controller or service 电子邮件功能有一个 `email` [服务](/cms/backend-customization/services),其中包含 2 个发送电子邮件的功能: 🌐 The Email feature has an `email` [service](/cms/backend-customization/services) that contains 2 functions to send emails: * `send()` 直接包含电子邮件内容, * `sendTemplatedEmail()` 从内容管理器获取数据以填充电子邮件,从而简化程序化电子邮件的流程。 #### 使用 `send()` 函数 {#using-the-send-function} 🌐 Using the `send()` function 要在用户操作后触发电子邮件,请将 `send()` 函数添加到 [控制器](/cms/backend-customization/controllers) 或 [服务](/cms/backend-customization/services)。发送函数具有以下属性: 🌐 To trigger an email in response to a user action add the `send()` function to a [controller](/cms/backend-customization/controllers) or [service](/cms/backend-customization/services). The send function has the following properties: | 属性 | 类型 | 描述 | |---------------|-------------------------------|--------------------------------------------------------------------------------------------------| | `from` | `string`(电子邮件地址)| 发件人地址。如果未指定,将使用来自 `plugins.js` 的 `defaultFrom`。 | | `to` | `string`(电子邮件地址)| 收件人地址。必填。 | | `cc` | `string`(电子邮件地址)| 抄送收件人。可选。| | `bcc` | `string`(电子邮件地址) | 密送收件人。可选。 | | `replyTo` | `string`(电子邮件地址)| 回复地址。如果未指定,则使用 `plugins.js` 中的 `defaultReplyTo`。| | `subject` | `string` | 电子邮件主题。必填。 | | `text` | `string` | 纯文本正文。需要 `text` 或 `html` 中的一个。 | | `html` | `string` | HTML 正文。必须提供 `text` 或 `html`。 | | `attachments` | `object[]` | 附件对象数组。 | | `headers` | `object` | 自定义 SMTP 头,例如 `{ 'X-Custom-Header': 'value' }`。 | | `priority` | `'high' \| 'normal' \| 'low'` | 邮件优先级标志。 | | `inReplyTo` | `string` | 被回复邮件的消息ID。用于会话线程。| | `references` | `string \| string[]` | 此电子邮件引用的消息 ID 列表。用于对话线程。 | | `envelope` | `object` | 带有 `from` 和 `to` 字段的自定义 SMTP 信封。用于退信处理。 | | `list` | `object` | RFC 2369 列表-* 头。支持在 Gmail 和 Outlook 中一键退订新闻通讯。 | | `icalEvent` | `object` | 以 iCalendar 格式的日历事件邀请。附加 `{ method, content }`。 | | `dsn` | `object` | 传递状态通知设置。请求退回或传递确认报告。 | :::note When using the Nodemailer provider Nodemailer 提供程序对所有 `send()` 字段使用显式允许列表。未知属性会被静默丢弃。有关支持字段的完整列表 —— 包括 `dkim`、`amp`、`raw`、`auth`(每条消息的 OAuth2)以及其他字段 —— 请参见 # 国际化 Source: https://docs.strapi.io/cms/features/internationalization # 国际化 (i18n) {#internationalization-i18n} 🌐 Internationalization (i18n) 国际化功能允许管理不同语言的内容,称为“本地化”。 🌐 The Internationalization feature allows to manage content in different languages, called "locales". 在 Strapi 的后端服务器上,文档服务 API 还可用于与本地化内容进行交互: 🌐 On the back-end server of Strapi, the Document Service API can also be used to interact with localized content: # 媒体库 Source: https://docs.strapi.io/cms/features/media-library # 媒体库 {#media-library} 🌐 Media Library 媒体库是 Strapi 的一个功能,它显示在 Strapi 应用中上传的所有资源,并允许用户进行管理。 :::info 本页面上的基于代码的配置说明详细列出了默认上传提供商的选项。如果使用其他提供商,请参阅该提供商文档中可用的配置参数。 🌐 Code-based configuration instructions on the present page detail options for the default upload provider. If using another provider, please refer to the available configuration parameters in that provider's documentation. ::: #### 可用选项 {#available-options} 🌐 Available options 在使用默认上传提供程序时,可以在[ `config/plugins` 文件](/cms/configurations/plugins)中的 `upload.config` 对象中声明以下特定配置选项。所有参数都是可选的: 🌐 When using the default upload provider, the following specific configuration options can be declared in an `upload.config` object within [the `config/plugins` file](/cms/configurations/plugins). All parameters are optional: | 参数 | 描述 | 类型 | 默认值 || --- | --- | --- | --- || `providerOptions.localServer` | 将传递给用于构建上传服务器的 #### 本地服务器 {#local-server} 🌐 Local server 默认情况下,Strapi 接受用于本地上传文件的 `localServer` 配置。这些将作为 #### 最大文件大小 {#max-file-size} 🌐 Max file size 负责解析请求的 Strapi 中间件需要配置以支持大于默认 200MB 的文件大小。这必须在为 `sizeLimit` 传递给 Upload 包的提供者选项之外进行配置。 🌐 The Strapi middleware in charge of parsing requests needs to be configured to support file sizes larger than the default of 200MB. This must be done in addition to provider options passed to the Upload package for `sizeLimit`. :::caution 你可能还需要调整任何上游代理、负载均衡器或防火墙以允许更大的文件大小。例如, 除了中间件配置之外,你还可以在 [/config/plugins 文件](/cms/configurations/plugins) 中传递 `sizeLimit`,它是以字节为单位的整数: 🌐 In addition to the middleware configuration, you can pass the `sizeLimit`, which is an integer in bytes, in the [/config/plugins file](/cms/configurations/plugins): #### 安全 #### 上传请求超时 {#upload-request-timeout} 🌐 Upload request timeout 默认情况下,`strapi.server.httpServer.requestTimeout` 的值设置为 330 秒。这包括上传。 🌐 By default, the value of `strapi.server.httpServer.requestTimeout` is set to 330 seconds. This includes uploads. 为了让网络连接缓慢的用户能够上传大文件,可能需要增加此超时限制。推荐的做法是通过在[ `config/servers` 文件](/cms/configurations/server)中设置 `http.serverOptions.requestTimeout` 参数来实现。 🌐 To make it possible for users with slow internet connection to upload large files, it might be required to increase this timeout limit. The recommended way to do it is by setting the `http.serverOptions.requestTimeout` parameter in [the `config/servers` file](/cms/configurations/server). 另一种方法是在 Strapi 启动之前运行的 [ `bootstrap` 函数](/cms/configurations/functions#bootstrap) 中设置 `requestTimeout` 值。这在需要以程序方式更改它的情况下非常有用——例如,暂时禁用然后重新启用它: 🌐 An alternate method is to set the `requestTimeout` value in [the `bootstrap` function](/cms/configurations/functions#bootstrap) that runs before Strapi gets started. This is useful in cases where it needs to change programmatically—for example, to temporarily disable and re-enable it: #### 响应式图片 {#responsive-images} 🌐 Responsive Images 当启用 [`Responsive friendly upload` 管理面板设置](#admin-panel-configuration) 时,插件将生成以下响应式图片尺寸: 🌐 When the [`Responsive friendly upload` admin panel setting](#admin-panel-configuration) is enabled, the plugin will generate the following responsive image sizes: | 名称 | 最大尺寸 || :------ | :--------- || 大型 | 1000px || 中型 | 750px || 小型 | 500px | 这些尺寸可以在 `/config/plugins` 中被覆盖: 🌐 These sizes can be overridden in `/config/plugins`: :::caution 断点更改仅适用于新图片,现有图片不会调整大小或生成新尺寸。 🌐 Breakpoint changes will only apply to new images, existing images will not be resized or have new sizes generated. ::: ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** ### 在你的代码中使用公共资源 {#public-assets} 🌐 Use public assets in your code 公共资源是指你希望外部访问的静态文件(例如,图片、视频、CSS 文件等)。 🌐 Public assets are static files (e.g., images, video, CSS files, etc.) that you want to make accessible to the outside world. 因为 API 可能需要提供静态资源,每个新的 Strapi 项目默认都会包含一个名为 `/public` 的文件夹。位于该目录中的任何文件,如果请求的路径不匹配任何其他已定义的路由,并且它匹配一个公共文件名(例如在 `./public/` 中名为 `company-logo.png` 的图片可通过 `/company-logo.png` URL 访问),则可以被访问。 🌐 Because an API may need to serve static assets, every new Strapi project includes by default a folder named `/public`. Any file located in this directory is accessible if the request's path doesn't match any other defined route and if it matches a public file name (e.g. an image named `company-logo.png` in `./public/` is accessible through `/company-logo.png` URL). :::tip `index.html` 文件会在请求对应于文件夹名称时提供(`/pictures` URL 会尝试提供 `public/pictures/index.html` 文件)。 ::: :::caution 点文件未被公开。这意味着每个以 `.` 开头的文件名,例如 `.htaccess` 或 `.gitignore`,都不会被提供服务。 🌐 The dotfiles are not exposed. It means that every file name that starts with `.`, such as `.htaccess` or `.gitignore`, are not served. ::: # 预览 Source: https://docs.strapi.io/cms/features/preview # 预览 {#preview} 🌐 Preview 通过预览功能,你可以直接在 Strapi 的管理面板中预览前端应用。这有助于查看在内容管理器的编辑视图中更新内容将如何影响最终结果。 🌐 With the Preview feature, you can preview your front end application directly from Strapi's admin panel. This is helpful to see how updates to your content in the Edit View of the Content Manager will affect the final result.
Next.js 中的缓存: 在 Next.js 中,[缓存持久化](https://next.nodejs.cn/docs/app/building-your-application/caching) 可能需要额外的步骤。你可能需要通过从客户端向服务器发起 API 调用来使缓存失效,其中会处理重新验证逻辑。有关详细信息,请参阅 Next.js 文档,例如使用 [revalidatePath() 方法](https://next.nodejs.cn/docs/app/building-your-application/caching#revalidatepath)。
#### 内容源映射 {#content-source-maps} 🌐 Content source maps 实时预览能够识别前端中对应于 Strapi 字段的部分。这是通过内容源映射完成的,内容源映射是作为隐藏字符编码在基于字符串的内容(例如文本字段)中的元数据。它使用 库来编码和解码这些元数据。 🌐 Live Preview is able to identify the parts of your frontend that correspond to fields in Strapi. This is done through content source maps, which are metadata encoded as hidden characters in your string-based content (e.g., text fields). It uses the library to encode and decode this metadata. 只有在将 `strapi-encode-source-maps` 头设置为 `true` 时,元数据才会添加到你的内容 API 响应中。你可以在数据获取工具中设置此头。确保仅在检测到你的网站在预览环境中呈现时才传递此头。 🌐 Metadatas will only be added in your Content API responses when the `strapi-encode-source-maps` header is set to `true`. You can set this header in your data fetching utility. Make sure to only pass the header when you detect that your site is rendered in a preview context. 对于 Next.js 应用,你可以使用来自 `next/headers` 的 `draftMode()` 方法来检测是否启用了草稿模式,并在所有 API 调用中相应地设置头信息: 🌐 For a Next.js application, you may use the `draftMode()` method from `next/headers` to detect if draft mode is enabled, and set the header accordingly in all your API calls: ```typescript {20-23} contentType: string, params: Record = {} ): Promise { // Check if Next.js draft mode is enabled const { isEnabled: isDraftMode } = await 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, { headers: { // Enable content source maps in preview mode "strapi-encode-source-maps": isDraftMode ? "true" : "false", }, }); 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; } } ``` ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** 内容管理器,编辑你的内容类型视图 :::strapi Preview vs. Live Preview 根据你的 CMS 计划,你使用预览的体验将有所不同: 🌐 Based on your CMS plan, your experience with Preview will be different: - 使用免费计划,预览将仅全屏显示。 - 使用 和 计划,你可以使用称为实时预览的增强功能。有了实时预览,你可以在内容管理器的编辑视图旁边查看预览,并且还可以通过双击任何内容直接在预览中编辑内容。 ::: 一旦预览功能设置正确,右侧的 [内容管理器编辑视图](/cms/features/content-manager#overview) 将显示一个 **打开预览** 按钮。点击它将直接在 Strapi 的管理面板中显示内容的预览效果,就像它在前端应用中显示的一样。 🌐 Once the Preview feature is properly set up, an **Open preview** button is visible on the right side of the [Content Manager's edit view](/cms/features/content-manager#overview). Clicking it will display the preview of your content as it will appear in your front-end application, but directly within Strapi's the admin panel. 打开预览后,你可以: 🌐 Once the Preview is open, you can: - 点击左上角的关闭按钮 返回内容管理器的编辑视图, - 使用预览内容上方的下拉菜单在桌面版和移动版预览之间切换, - 在预览草稿和已发布版本之间切换(如果该内容类型启用了 [草稿与发布](/cms/features/draft-and-publish) 功能), - 然后点击右上角的链接图标 以复制预览链接。根据你当前查看的预览标签,这将复制草稿预览的链接或已发布版本的链接。 :::note 在内容管理器的编辑视图中,如果你有未保存的更改,‘打开预览’按钮将被禁用。保存你最近的更改后,你应该可以再次预览内容。 🌐 In the Edit view of the Content Manager, the Open preview button will be disabled if you have unsaved changes. Save your latest changes and you should be able to preview content again. ::: ### 实时预览 {#live-preview} 🌐 Live Preview 实时预览是 Strapi 付费 CMS 方案提供的增强预览体验。 🌐 Live Preview is the enhanced Preview experience available with Strapi’s paid CMS plans. 使用实时预览功能,除了免费套餐中包含的功能外,你还可以: 🌐 With Live Preview, in addition to what’s included in the Free plan, you can: * 使用侧边编辑器可以同时查看内容管理器中条目的编辑视图和前端预览。你还可以使用 和 按钮在全屏预览和并排预览之间切换。 * 在预览窗格中双击任意内容即可进行原位编辑。这将打开一个弹出窗口,将前端内容与 Strapi 中的对应字段同步。 :::caution Experimental feature 此功能目前处于实验阶段。欢迎随时与 Strapi 团队分享 或 。 当前版本的实时预览存在以下限制: 🌐 The current version of Live Preview comes with the following limitations: * 块字段无法被检测到,在侧边编辑器中更改它们不会在预览中反映。然而,更新后点击保存仍然应该有效。 * 动态区域中的媒体资源和字段不予处理。 ::: # 基于角色的访问控制(RBAC) Source: https://docs.strapi.io/cms/features/rbac # 基于角色的访问控制(RBAC) {#role-based-access-control-rbac} 🌐 Role-Based Access Control (RBAC) 基于角色的访问控制(RBAC)功能允许管理管理员,即管理面板的用户。更具体地说,RBAC 管理管理员的账户和角色。 🌐 The Role-Based Access Control (RBAC) feature allows the management of the administrators, who are the users of the admin panel. More specifically, RBAC manages the administrators' accounts and roles. 4. 点击右上角的**保存**按钮。 :::tip 要为你的自定义插件创建管理员权限,请参考我们的[专用指南](/cms/plugins-development/guides/admin-permissions-for-plugins)。 🌐 To create admin permissions for your custom plugin, please refer to our [dedicated guide](/cms/plugins-development/guides/admin-permissions-for-plugins). ::: #### 为权限设置自定义条件 {#setting-custom-conditions-for-permissions} 🌐 Setting custom conditions for permissions 对于每个类别的每个权限,都会显示一个 ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** *设置 > 管理面板 > 用户* *用户*界面显示一个表格,列出你 Strapi 应用的所有管理员。更具体地说,对于表格中列出的每个管理员,其主要账户信息都会显示,包括名称、电子邮件和分配的角色。账户状态也会被指示:激活或未激活,这取决于管理员是否已经登录以激活账户。 🌐 The *Users* interface displays a table listing all the administrators of your Strapi application. More specifically, for each administrator listed in the table, their main account information are displayed, including name, email and attributed role. The status of their account is also indicated: active or inactive, depending on whether the administrator has already logged in to activate the account or not. 通过该界面,可以: 🌐 From this interface, it is possible to: - 进行文本搜索 以查找特定的管理员, - 设置筛选器 以查找特定管理员, - 创建一个新的管理员账户(参见 [创建新账户](#creating-a-new-account)) , - 删除管理员账户 (参见[删除账户](#deleting-an-account)), - 或访问有关管理员账户的信息,并编辑它 (参见[编辑账户](#editing-an-account))。 :::tip 表中显示的大多数字段都可以启用排序。点击表头中的字段名称,即可对该字段进行排序。 🌐 Sorting can be enabled for most fields displayed in the table. Click on a field name, in the header of the table, to sort on that field. ::: ### 创建新账户 {#creating-a-new-account} 🌐 Creating a new account 1. 点击 **邀请新用户**按钮。 2. 在*邀请新用户*窗口中,填写关于新管理员的详细信息: | 用户信息 | 说明 || ---------------- | ---------------------------------------------------------------------------- || 名字 | (必填)在文本框中填写管理员的名字。 || 姓氏 | (必填)在文本框中填写管理员的姓氏。 || 电子邮件 | (必填)在文本框中填写管理员的完整电子邮件地址。 | 3. 填写新管理员的登录设置: | 设置 | 说明 | | ---------------- | --------------------------------------------------------------------------------------------------------------- | | 用户角色 | (必填)从下拉列表中选择要分配给新管理员的角色。 | | 连接 SSO | (可选)点击 **TRUE** 或 **FALSE** 将新管理员账户与 SSO 连接。 | 4. 在 *添加新用户* 窗口的右下角点击 **邀请用户** 按钮。 5. 窗口顶部会显示一个 URL:这是发送给新管理员以便他们首次登录你的 Strapi 应用的 URL。点击复制按钮 以复制该 URL。 6. 点击右下角的 **完成** 按钮以完成新管理员账户的创建。新管理员现在应该会出现在表格中。 :::note 管理员邀请 URL 可从管理员账户访问,直至激活。 🌐 The administrator invitation URL is accessible from the administrator's account until it has been activated. ::: ### 删除账户 {#deleting-an-account} 🌐 Deleting an account 可以同时删除一个或多个管理员账户。 🌐 It is possible to delete one or several administrator accounts at the same time. 1. 点击账户记录右侧的删除按钮 ,或通过勾选账户记录左侧的框选择一个或多个账户,然后点击表格上方的 **删除**按钮。 2. 在删除窗口中,点击 **确认** 按钮以确认删除。 ### 编辑账户 {#editing-an-account} 🌐 Editing an account 1. 单击要编辑其账户的管理员的名称。 2. 在*详细信息*区域,编辑你选择的账户详细信息: | 用户信息 | 操作说明 || --- | --- || 名字 | 在文本框中输入管理员的名字。 || 姓氏 | 在文本框中输入管理员的姓氏。 || 电子邮件 | 在文本框中输入管理员的完整电子邮件地址。 || 用户名 | 在文本框中输入管理员的用户名。 || 密码 | 在文本框中输入新管理员账户的密码。 || 确认密码 | 在文本框中再次输入新密码以确认。 || 激活 | 点击 **TRUE** 以激活管理员账户。 | 3. (可选) 在*角色*区域,编辑管理员的角色: - 单击下拉列表选择一个新角色,和/或将其添加到已归属的角色中。 - 点击删除按钮 以删除已分配的角色。 4. 点击右上角的**保存**按钮。 # 发布 Source: https://docs.strapi.io/cms/features/releases # 发布 发布功能使内容管理员能够将条目组织到可以同时执行发布和取消发布操作的容器中。一个发布可以包含来自不同内容类型的条目,并且可以混合不同的语言环境。 🌐 The Releases feature enables content managers to organize entries into containers that can perform publish and unpublish actions simultaneously. A release can contain entries from different content types and can mix locales. ## 配置 {#configuration} 🌐 Configuration 要能够将你的内容包含在发布中,并安排和发布这些发布,你必须首先创建它们。你还可以修改发布在安排发布时使用的默认时区,以及删除过时或无关的发布。 🌐 To be able to include your content in releases, and to schedule and publish those releases, you must first create them. You can also modify the releases' default timezone to use when scheduling a publication, as well as deleting releases that are obsolete or irrelevant. ### 选择默认时区 {#choosing-default-timezone} 🌐 Choosing default timezone **配置此功能的路径:** 设置 1. 点击“默认时区”下拉列表,并选择要使用的默认时区。 2. 点击 **保存**。 ### 创建发布 {#creating-a-release} 🌐 Creating a release **配置该功能的路径:** 版本 1. 点击右上角的 **新发布**按钮。 2. 为发布命名。 3. (_可选_) 如果你想安排发布而不是手动发布,请勾选 **安排发布** 复选框,并定义发布时间、日期和时区。 4. 点击 **继续** 按钮。 :::tip 你的发布之后可以重命名,通过使用 然后 **编辑**按钮来编辑发布。 ::: ### 删除版本 {#deleting-a-release} 🌐 Deleting a release **路径:** 发布 删除版本只会删除版本本身,而不会删除版本中包含的内容类型条目。 🌐 Deleting a release will only delete the release itself, but not the content-type entries included in the release. 1. 点击管理员面板右上角的 按钮。 2. 选择 **删除**。 3. 在确认对话框中,点击 **确认**。 ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** 版本和 内容管理器 :::caution 由于发布带有发布版本的条目意味着将草稿条目变为已发布条目,因此如果内容类型的[草稿和发布](/cms/features/draft-and-publish)被禁用,发布版本将无法使用。 🌐 Since publishing an entry with a release means turning a draft entry into a published entry, Releases will not work if [Draft & Publish](/cms/features/draft-and-publish) is disabled for the content-type. ::: ### 在发布中包含内容 {#including-content-in-a-release} 🌐 Including content in a release :::prerequisites - 在可以向发行版添加条目之前,你必须先从 发行页面创建一个发行版。 - 向发行版添加内容需要具有 Content-Releases 插件的适当权限(参见 [配置管理员角色](/cms/features/users-permissions))。 ::: #### 一次输入一个 {#one-entry-at-a-time} 🌐 One entry at a time **路径:** 内容管理器的编辑视图 1. 点击界面右侧_Entry_区域的 。 2. 在列表中,点击 **添加到版本**按钮。 2. 选择要将此条目添加到哪个版本。 3. 根据你希望在发布版本发布时条目是发布还是取消发布,点击 **发布** 或 **取消发布** 按钮,然后点击 **继续**。 右边的 *Releases* 框应显示该条目包含在哪些版本中。 🌐 The *Releases* box on the right should show which release(s) the entry is included in. :::info 如果启用了[版本计划](/cms/features/releases#scheduling-a-release)并且条目已被添加到计划发布中,则也会显示发布日期和时间。 🌐 If [Releases scheduling](/cms/features/releases#scheduling-a-release) is enabled and the entry is added to a scheduled release, the release date and time will also be displayed. ::: #### 一次输入多个条目 {#multiple-entries-at-a-time} 🌐 Multiple entries at a time **路径:** 内容管理器的列表视图 1. 通过勾选条目记录左侧的框来选择要添加的条目。 2. 点击位于表格标题上方的 **添加到发布** 按钮。 3. 在模式中,选择要将这些条目添加到哪个版本。 4. 点击 **发布** 或 **取消发布** 按钮,以决定这些条目在发布版本发布时是要发布还是取消发布,然后点击 **继续**。 ### 从版本中移除内容 {#removing-an-entry-from-a-release} 🌐 Removing content from a release **路径:** 内容管理器的编辑视图 1. 在右侧边栏的 *Releases* 框中,点击发行版名称下方的 。 2. 点击 **从版本中移除** 按钮。 ### 安排发布 {#scheduling-a-release} 🌐 Scheduling a release **路径:** 发布 版本可以[手动发布](#publishing-a-release),也可以安排在指定日期和时间自动发布,并选择你希望的时区。 🌐 Releases can be [published manually](#publishing-a-release) or scheduled to be automatically published at a given date and time, with the timezone of your choice. 你可以安排发布: 🌐 You can schedule a release: - 在[创建版本](#creating-a-release)时, - 或者一旦创建了版本,就可以对其进行编辑。 要在发布页面上安排现有发布: 🌐 To schedule an existing release, while on a release page: 1. 点击管理员面板右上角的 按钮。 2. 选择 **编辑**。 3. 在模态窗口中,勾选 **安排发布** 复选框。 4. 选择要发布的版本的日期、时间和时区。 5. 点击 **保存**。 ### 发布版本 {#publishing-a-release} 🌐 Publishing a release **路径:** 发布 发布版本意味着为版本中包含的每个条目定义的所有操作(发布或取消发布)将同时执行。 🌐 Publishing a release means that all the actions (publish or unpublish) defined for each entry included in the release will be performed simultaneously. 要发布版本,请点击管理面板右上角的 **发布** 按钮。在此之前,请确保检查版本及其条目的状态。 🌐 To publish a release, click the **Publish** button in the top right corner of the admin panel. Before, make sure to check the status of both the release and its entries. - 界面顶部的徽章指示你的发布状态: - `Empty`:尚未将任何条目添加到发布版本 - `Blocked`:内容已添加到发布版本,但条目中至少有一个问题阻止发布版本 - `Ready`:内容已添加到发布版本,所有检查均已通过,可以发布发布版本 - `Done`:发布版本已发布,现已完成 - _状态_ 列显示每个条目的状态: - 已发布:该条目已发布,发布此版本不会影响此条目 - 已取消发布:该条目已取消发布,发布此版本不会影响该条目。 - 准备发布:条目已准备好随版本发布 - 准备撤稿:该条目已准备好随发布一起撤销 - 未准备好发布:该条目无法发布,因为某些字段填写不正确,或尚未达到发布所需的阶段。在这种情况下,发布状态将显示为*阻止*,直到所有问题都得到解决。 如果你的版本是 `Blocked`,因为你的一些条目有 状态,点击 按钮,然后**编辑条目**以修复问题,直到所有条目都有 状态。 :::note 在你修复各种条目问题时,你需要点击 **刷新** 按钮以更新发布页面。 🌐 You will have to click on the **Refresh** button to update the release page as you fix the various entries issues. ::: :::caution 一旦发布了版本,该版本本身无法更新。你不能使用同一组条目进行一些修改后重新发布该特定版本;你必须创建另一个版本。 🌐 Once a release is published, the release itself cannot be updated. You can not re-release that specific release with the same group of entries with some modifications; you must create another release. ::: # 审查工作流程 Source: https://docs.strapi.io/cms/features/review-workflows # 审查工作流程 审核工作流功能允许你为各种内容类型创建和管理工作流。每个工作流可以包含内容的任何审核阶段,使你的团队能够在从草稿到发布的内容创建流程中进行协作。 🌐 The Review Workflows feature allows you to create and manage workflows for your various content-types. Each workflow can consist of any review stages for your content, enabling your team to collaborate in the content creation flow from draft to publication. ## 配置 {#configuration} 🌐 Configuration **配置此功能的路径:** 设置 > 全局设置 > 审核工作流 为了使审核工作流可以在 [内容管理器](/cms/features/content-manager) 中使用,应配置默认工作流或创建新的工作流。 🌐 For the review workflows to be usable in the [Content Manager](/cms/features/content-manager), the default one should be configured or a new one should be created. 默认工作流程配置为包含 4 个阶段:待办、进行中、待审查和已审查。所有 4 个阶段都可以根据需要进行编辑、重新排序或删除,也可以添加新阶段。 🌐 The default workflow is configured to have 4 stages: To do, In progress, Ready to review, and Reviewed. All 4 stages can be edited, reordered or deleted as needed, and it is also possible to add new stages. ### 创建新工作流程 {#creating-a-new-workflow} 🌐 Creating a new workflow 1. 点击 **创建新工作流** 按钮或工作流的编辑按钮 。 2. 在工作流编辑界面中,配置新的工作流: | 设置名称 | 说明 || -------------- | --------------------------------------------------------------------- || 工作流名称 | 为工作流写一个唯一的名称。 || 关联对象 | (可选)将此工作流分配给一个或多个现有内容类型。 || 阶段 | 添加审核阶段(参见 [添加新阶段](#adding-a-new-stage))。 3. 点击 **保存** 按钮。新的工作流将显示在列表视图中,并适用于每个分配的内容类型。 :::note 最大数量为 。 ::: ### 编辑工作流程 {#editing-a-workflow} 🌐 Editing a workflow #### 添加新阶段 {#adding-a-new-stage} 🌐 Adding a new stage 1. 点击**添加新阶段**按钮。 2. 写下*艺名*。 3. 选择一个*颜色*。 4. 选择可以更改阶段的*角色*,前提是实体当前处于该审核阶段。 5. 点击 **保存** 按钮。 默认情况下,新阶段会被追加,但可以随时使用 按钮重新排序。 :::tip 要为每个阶段设置角色,你可以点击“应用到所有阶段”将当前角色应用到工作流的所有其他阶段,或者使用阶段上下文菜单中的“复制阶段”。 🌐 To set up roles for each stage, you can either click "Apply to all stages" to apply the current roles to all other stages of the workflow or use "Duplicate stage" of the stage context menu. ::: #### 复制一个阶段 {#duplicating-a-stage} 🌐 Duplicating a stage 1. 在舞台的上下文菜单中点击 **复制舞台**。 2. 更改复制阶段的名称。 2. 点击 **保存** 按钮。 #### 删除一个阶段 {#deleting-a-stage} 🌐 Deleting a stage 要删除一个阶段,请在该阶段的上下文菜单中点击 ,然后选择**删除**。 如果你删除一个有待审核的阶段,审核将被移到工作流中的第一个阶段。每个工作流必须至少包含一个阶段,因此不可能删除最后一个阶段。 🌐 If you delete a stage that has pending reviews, the reviews will be moved to first stage in the workflow. Every workflow needs to contain at least one stage and therefore it is not possible to delete the last stage. ### 删除工作流 {#deleting-a-workflow} 🌐 Deleting a workflow 要删除工作流,请在列表视图中点击工作流的删除按钮 。 :::note 无法删除最后一个工作流程。 🌐 It is not possible to delete the last workflow. ::: ## 使用 {#usage} 🌐 Usage **使用此功能的路径:** 内容管理器 ### 更改审查阶段 {#change-review-stage} 🌐 Changing review stage 随着你的团队创建和修改内容,你可以将内容的审核阶段更改为审核工作流中定义的任何阶段。 🌐 As content is created and revised among your team, you can change the review stage of the content to any stage defined in the review workflow. 1. 访问你的内容类型的编辑视图。 2. 在界面右侧的*审查工作流*框中,点击_审查阶段_下拉列表。 3. 选择你的条目的新审核阶段。它会自动保存。 ### 定义受让人 {#change-assignee} 🌐 Defining assignee 审核工作流程内容类型的条目可以分配给 Strapi 中的任何管理员用户进行审核。 🌐 Entries of a review workflow content type can be assigned to any admin user in Strapi for review. 1. 访问你的内容类型的编辑视图。 2. 在界面右侧的*审查工作流*框中,点击_受托人_下拉列表。 3. 选择你的条目的新受让人。它会自动保存。 # 单点登录 (SSO) Source: https://docs.strapi.io/cms/features/sso # 单点登录 (SSO) 可以在 Strapi 应用上提供单点登录 (SSO) 功能,以允许管理员通过身份提供者(例如 Microsoft Azure Active Directory)进行身份验证。 🌐 The Single Sign-On (SSO) feature can be made available on a Strapi application to allow administrators to authenticate through an identity provider (e.g. Microsoft Azure Active Directory). ## 使用 {#usage} 🌐 Usage 要使用特定提供商访问管理面板,而不是使用常规 Strapi 管理员账户登录: 🌐 To access the admin panel using a specific provider instead of logging in with a regular Strapi administrator account: 1. 转至 Strapi 应用管理面板的 URL。 2. 点击所选提供商,其徽标应显示在登录表单底部。如果你看不到你的提供商,请点击 按钮以访问所有可用提供商的完整列表。 3. 你将被重定向到提供者自己的登录页面,你可以在其中进行身份验证。 # 用户与权限 Source: https://docs.strapi.io/cms/features/users-permissions # 用户与权限 {#users--permissions} 🌐 Users & Permissions “用户与权限”功能允许管理 Strapi 项目的终端用户 它提供基于 JSON Web Token(JWT)的完整身份验证流程来保护你的 API,并且提供访问控制列表(ACL)策略,使你能够管理用户组之间的权限。 ## 管理面板配置 {#admin-panel-configuration} 🌐 Admin panel configuration 用户和权限功能可从管理面板设置和代码库进行配置。 🌐 The Users & Permissions feature is configured from both the admin panel settings, and via the code base. ### 角色 {#roles} 🌐 Roles 用户和权限功能允许为终端用户创建和管理角色,以配置他们可以访问的内容。 🌐 The Users & Permissions feature allows to create and manage roles for end users, to configure what they can have access to. #### 创建新角色 {#creating-a-new-role} 🌐 Creating a new role **路径:** ### 电子邮件模板 {#email-templates} 🌐 Email templates **路径:** ### 注册配置 {#registration-configuration} 🌐 Registration configuration 如果你在你的用户 **模型** 需要在注册时被接受的字段,你需要将它们添加到 [the `/config/plugins` file](/cms/configurations/plugins) 中 `config.register` 对象的允许字段列表,否则它们将不会被接受。 以下示例展示了如何确保在用户注册时 API 接受名为“nickname”的字段: 🌐 The following example shows how to ensure a field called "nickname" is accepted by the API on user registration: ### 速率限制配置 {#rate-limiting-configuration} 🌐 Rate limiting configuration 对身份验证和注册端点应用速率限制以防止滥用。可以配置以下参数以更改其行为。 ### 邮件模板化 {#templating-emails} 🌐 Templating emails 默认情况下,这个插件附带两个模板:重置密码和邮箱地址确认。模板使用 ### 安全配置 {#security-configuration} 🌐 Security configuration JWT 可以被验证和信任,因为信息是经过数字签名的。要签署令牌需要一个 _secret_。默认情况下,Strapi 会生成并将其存储在 `/extensions/users-permissions/config/jwt.js` 中。 🌐 JWTs can be verified and trusted because the information is digitally signed. To sign a token a _secret_ is required. By default Strapi generates and stores it in `/extensions/users-permissions/config/jwt.js`. 这在开发过程中非常有用,但出于安全原因,建议在部署到生产环境时通过环境变量 `JWT_SECRET` 设置自定义令牌。 🌐 This is useful during development but for security reasons it is recommended to set a custom token via an environment variable `JWT_SECRET` when deploying to production. 默认情况下,你可以设置一个 `JWT_SECRET` 环境变量,它将被用作密钥。如果你想使用另一个变量,可以更新配置文件。 🌐 By default you can set a `JWT_SECRET` environment variable and it will be used as secret. If you want to use another variable you can update the configuration file. #### 创建自定义回调验证器 {#creating-a-custom-password-validation} 🌐 Creating a custom callback validator 默认情况下,Strapi SSO 仅重定向到与配置中的 URL 完全相等的重定向 URL: 🌐 By default, Strapi SSO only redirects to the redirect URL that is exactly equal to the url in the configuration: 要退出所有会话,请发送以下请求: 🌐 To log out of all sessions, send the following request: #### 标识符 {#identifier} 🌐 Identifier 随请求发送的 `identifier` 参数可以是电子邮件或用户名,如以下示例所示: 🌐 The `identifier` parameter sent with requests can be an email or username, as in the following examples: #### 令牌使用 {#token-usage} 🌐 Token usage `jwt` 然后可以用来进行受权限限制的 API 请求。要以用户身份进行 API 请求,请将 JWT 放入 `GET` 请求的 `Authorization` 头中。 🌐 The `jwt` may then be used for making permission-restricted API requests. To make an API request as a user place the JWT into an `Authorization` header of the `GET` request. 任何没有令牌的请求将默认假定 `public` 角色权限。在管理面板中修改每个用户角色的权限。 🌐 Any request without a token will assume the `public` role permissions by default. Modify the permissions of each user's role in the admin dashboard. 身份验证失败会返回 `401 (unauthorized)` 错误。 🌐 Authentication failures return a `401 (unauthorized)` error. `token` 变量是登录或注册时接收到的 `data.jwt`。 🌐 The `token` variable is the `data.jwt` received when logging in or registering. ```js const token = 'YOUR_TOKEN_HERE'; // Request API. axios .get('http://localhost:1337/posts', { headers: { Authorization: `Bearer ${token}`, }, }) .then(response => { // Handle success. console.log('Data: ', response.data); }) .catch(error => { // Handle error. console.log('An error occurred:', error.response); }); ``` #### 用户注册 {#user-registration} 🌐 User registration 在数据库中创建一个新的用户,并将默认角色设置为“注册用户”,可以像以下示例一样进行: 🌐 Creating a new user in the database with a default role as 'registered' can be done like in the following example: ```js // Request API. // Add your own code here to customize or restrict how the public can register new users. axios .post('http://localhost:1337/api/auth/local/register', { username: 'Strapi user', email: 'user@strapi.io', password: 'strapiPassword', }) .then(response => { // Handle success. console.log('Well done!'); console.log('User profile', response.data.user); console.log('User token', response.data.jwt); }) .catch(error => { // Handle error. console.log('An error occurred:', error.response); }); ``` #### Strapi 上下文中的用户对象 {#user-object-in-strapi-context} 🌐 User object in Strapi context `user` 对象可供成功认证的请求使用。 🌐 The `user` object is available to successfully authenticated requests. 经过验证的 `user` 对象是 `ctx.state` 的一个属性。 🌐 The authenticated `user` object is a property of `ctx.state`. ```js create: async ctx => { const { id } = ctx.state.user; const depositObj = { ...ctx.request.body, depositor: id, }; const data = await strapi.services.deposit.add(depositObj); // Send 201 `created` ctx.created(data); }; ``` # 安装 Source: https://docs.strapi.io/cms/installation # 安装 {#installation} 🌐 Installation Strapi 项目可以安装在本地计算机或远程服务器上。以下安装指南提供了在本地机器上安装和创建新 Strapi 项目的逐步说明: 🌐 Strapi projects can be installed either locally on a computer or on a remote server. The following installation guide provides step-by-step instructions on how to install and create a new Strapi project on your local machine: 如果你的本地机器上已经有现有的 Strapi 项目,以下指南提供了为你的项目创建自定义 Docker 映像的分步说明: 🌐 If you already have an existing Strapi project on your local machine, the following guide provides step-by-step instructions on creating a custom Docker image for your project: # 迁移到 Strapi 5 的额外资源 Source: https://docs.strapi.io/cms/migration/v4-to-v5/additional-resources/introduction # 升级到 Strapi 5 的额外资源 {#additional-resources-for-upgrading-to-strapi-5} 🌐 Additional resources for upgrading to Strapi 5 以下页面涵盖了升级到 Strapi 5 时针对特定使用案例的一些专门主题。请确保在继续之前已阅读 [升级到 Strapi 5 介绍](/cms/migration/v4-to-v5/introduction-and-faq) 和 [逐步指南](/cms/migration/v4-to-v5/step-by-step)。 🌐 The following pages cover some dedicated topics for specific use cases when upgrading to Strapi 5. Please ensure you have read the [introduction to upgrading to Strapi 5](/cms/migration/v4-to-v5/introduction-and-faq) and [step-by-step guide](/cms/migration/v4-to-v5/step-by-step) before moving forward. # 重大变更 Source: https://docs.strapi.io/cms/migration/v4-to-v5/breaking-changes # Strapi v4 到 Strapi 5 的重大变更 {#strapi-v4-to-strapi-5-breaking-changes} 🌐 Strapi v4 to Strapi 5 breaking changes 本页面列出了 Strapi 5 中引入的所有重大更改。重大更改按主题相关类别分组,在下面表格的每一行中,你将找到: 🌐 The present page lists all the breaking changes introduced in Strapi 5. Breaking changes are grouped into topic-related categories, and for each line in the following tables line you will find: - 重大更改的简短描述, - 以及另外两列,“影响插件”和“由 codemods 处理”,总结了破坏性更改是否也影响插件,以及破坏性更改是否由 [升级 CLI 工具](/cms/upgrade-tool) 的 codemod 自动处理。 你可以单击下表中任何重大更改的描述以跳转到包含更多详细信息的相应页面。 🌐 You can click on the description of any breaking change in the following tables to jump to the corresponding page with more details. :::tip Tips * 要查看可用 codemods 的完整列表,请在终端中运行 `npx @strapi/upgrade codemods ls` 命令。 * 要更深入地查看 codemods 执行的代码,请前往 GitHub 仓库中的 。 ::: ## 数据库 {#database} 🌐 Database | 描述 | 影响插件 | 由 codemods 处理 ||-------------|-----------------|---------------------|| [内容类型总是有功能列](/cms/migration/v4-to-v5/breaking-changes/database-columns) | 是 | 否 || [不再支持 MySQL v5](/cms/migration/v4-to-v5/breaking-changes/mysql5-unsupported) | 否 | 否 || [数据库标识符超过 55 个字符将被自动缩短](/cms/migration/v4-to-v5/breaking-changes/database-identifiers-shortened) | 是 | ✅ 是 || [SQLite 客户端仅支持 `better-sqlite3` 包](/cms/migration/v4-to-v5/breaking-changes/only-better-sqlite3-for-sqlite) | 否 | ✅ 是 || [MySQL 客户端仅支持 `mysql2` 包](/cms/migration/v4-to-v5/breaking-changes/only-mysql2-package-for-mysql) | 否 | ✅ 是 | ## 依赖 {#dependencies} 🌐 Dependencies | 描述 | 影响插件 | 由代码修改工具处理 ||-------------|-----------------|---------------------|| [CLI 默认的包管理器不再是 yarn](/cms/migration/v4-to-v5/breaking-changes/yarn-not-default) | 否 | 否 || [Vite 是 Strapi 5 的默认打包工具](/cms/migration/v4-to-v5/breaking-changes/vite) | 是 | 否 || [Strapi 5 使用 `react-router-dom` v6](/cms/migration/v4-to-v5/breaking-changes/react-router-dom-6) | 是 | ✅ 是 || [Strapi 5 使用 `koa-body` v6](/cms/migration/v4-to-v5/breaking-changes/koa-body-v6) | 是 | 否 || [Strapi 5 中移除了 Webpack 别名](/cms/migration/v4-to-v5/breaking-changes/webpack-aliases-removed) | 是 | 否 || [Apollo Server v3 升级到 Apollo Server v4](/cms/migration/v4-to-v5/breaking-changes/upgrade-to-apollov4) | 是 | 否 | ## 配置 {#configuration} 🌐 Configuration | 描述 | 影响的插件 | 由代码转换处理 | |-------------|-----------------|---------------------| | [一些仅适用于 `env` 的配置选项由服务器配置处理](/cms/migration/v4-to-v5/breaking-changes/removed-support-for-some-env-options) | 否 | 否 | | [配置文件名应符合严格要求](/cms/migration/v4-to-v5/breaking-changes/strict-requirements-config-files) | 否 | 否 | | [服务器日志级别是 `http`](/cms/migration/v4-to-v5/breaking-changes/server-default-log-level) | 否 | 否 | | [模型配置路径使用 UID 而不是点表示法](/cms/migration/v4-to-v5/breaking-changes/model-config-path-uses-uid) | 是 | 👷 部分 | | [`webhooks.populateRelations` 服务器配置已删除](/cms/migration/v4-to-v5/breaking-changes/remove-webhook-populate-relations) | 是 | 否 | | [在 `public` 中移除了 `defaultIndex` 选项](/cms/migration/v4-to-v5/breaking-changes/default-index-removed) | 否 | 否 | | [服务器代理配置选项分组在 `server.proxy` 对象下](/cms/migration/v4-to-v5/breaking-changes/server-proxy) | 否 | 否 | ## Strapi 对象、方法、包和后端自定义 {#strapi-objects-methods-packages-and-back-end-customization} 🌐 Strapi objects, methods, packages, and back-end customization | 描述 | 影响插件 | 由代码修改工具处理 ||-------------|-----------------|---------------------|| [`strapi.fetch` 使用原生 `fetch()` API](/cms/migration/v4-to-v5/breaking-changes/fetch) | 是 | 否 || [strapi 工厂导入已更改](/cms/migration/v4-to-v5/breaking-changes/strapi-imports) | 是 | 👷 部分 || [`isSupportedImage` 方法在 Strapi 5 中已移除](/cms/migration/v4-to-v5/breaking-changes/is-supported-image-removed) | 是 | 否 || [`strapi-utils` 已被重构](/cms/migration/v4-to-v5/breaking-changes/strapi-utils-refactored) | 是 | ✅ 是 || [核心服务方法使用 Document Service API](/cms/migration/v4-to-v5/breaking-changes/core-service-methods-use-document-service) | 是 | 否 || [i18n 现在是 strapi 核心的一部分](/cms/migration/v4-to-v5/breaking-changes/i18n-content-manager-locale) | 是 | ✅ 是 | ## 插件、提供商、管理面板和前端自定义 {#plugins-providers-admin-panel-and-front-end-customization} 🌐 Plugins, providers, admin panel and front-end customization | 描述 | 影响的插件 | 由代码转换处理 | |-------------|-----------------|---------------------| | [用户与权限 `register.allowedFields` 默认为 `[]`](/cms/migration/v4-to-v5/breaking-changes/register-allowed-fields) | 否 | ✅ 是 | | [`helper-plugin` 已被移除](/cms/migration/v4-to-v5/breaking-changes/helper-plugin-deprecated) | 是 | 👷 部分 | | [`injectContentManagerComponent()` 被移除,改用 `getPlugin('content-manager').injectComponent()`](/cms/migration/v4-to-v5/breaking-changes/inject-content-manager-component) | 是 | 否 | | [某些 Mailgun 提供商的旧变量不受支持](/cms/migration/v4-to-v5/breaking-changes/mailgun-provider-variables) | 是 | 否 | | [`lockIcon` 属性已被 `licenseOnly` 取代](/cms/migration/v4-to-v5/breaking-changes/license-only) | 是 | 否 | | [`ContentManagerAppState` redux 已被修改](/cms/migration/v4-to-v5/breaking-changes/redux-content-manager-app-state) | 是 | 否 | | [“EditViewLayout”和“ListViewLayout”已被重构](/cms/migration/v4-to-v5/breaking-changes/edit-view-layout-and-list-view-layout-rewritten) | 是 | 否 | | [管理面板 RBAC redux 存储已更新](/cms/migration/v4-to-v5/breaking-changes/admin-panel-rbac-store-updated) | 是 | 否 | | [`getWhere` 方法用于权限提供者实例已被删除](/cms/migration/v4-to-v5/breaking-changes/get-where-removed) | 是 | 否 | | [设计系统已升级](/cms/migration/v4-to-v5/breaking-changes/design-system) | 是 | 否 | ## 内容 API {#content-api} 🌐 Content API | 描述 | 影响的插件 | 由代码转换处理 | |-------------|-----------------|---------------------| | [Strapi 5 为 API 调用提供了新的扁平化响应格式](/cms/migration/v4-to-v5/breaking-changes/new-response-format) | 是 | 否 | | [REST API 输入在控制器中默认被验证](/cms/migration/v4-to-v5/breaking-changes/default-input-validation) | 是 | 否 | | [GraphQL API 已更新](/cms/migration/v4-to-v5/breaking-changes/graphql-api-updated) | 是 | 否 | | [实体服务 API 已弃用,已被文档服务 API 取代](/cms/migration/v4-to-v5/breaking-changes/entity-service-deprecated) | 是 | 👷 部分 | | [`documentId` 应该在 API 调用中替代 `id`](/cms/migration/v4-to-v5/breaking-changes/use-document-id) | 是 | 👷 部分 | | [根据文档服务 API 方法,数据库生命周期钩子的触发方式不同](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service) | 是 | 否 | | [`publicationState` 参数不受支持,已被 `status` 取代](/cms/migration/v4-to-v5/breaking-changes/publication-state-removed) | 是 | ✅ 是 | | [禁用草稿和发布的内容类型始终将 publishedAt 值设置为日期](/cms/migration/v4-to-v5/breaking-changes/publishedat-always-set-when-dandp-disabled) | 是 | 否 | | [按 ID 排序不再能按时间顺序排序](/cms/migration/v4-to-v5/breaking-changes/sort-by-id) | 是 | ✅ 是 | | [在文档服务 API 中没有 `findPage()` 方法](/cms/migration/v4-to-v5/breaking-changes/no-find-page-in-document-service) | 是 | 否 | | [某些属性和内容类型名称被 Strapi 保留](/cms/migration/v4-to-v5/breaking-changes/attributes-and-content-types-names-reserved) | 是 | 否 | | [在创建条目时上传文件不再可能](/cms/migration/v4-to-v5/breaking-changes/no-upload-at-entry-creation) | 是 | 否 | | [组件和动态区域应使用详细的填充策略进行填充](/cms/migration/v4-to-v5/breaking-changes/no-shared-population-strategy-components-dynamic-zones) | 是 | 否 | | [不建议使用文档服务 API 更新可重复使用的组件](/cms/migration/v4-to-v5/breaking-changes/do-not-update-repeatable-components-with-document-service-api) | 是 | 否 | # 升级到 Strapi 5 - 简介和常见问题 Source: https://docs.strapi.io/cms/migration/v4-to-v5/introduction-and-faq # 升级到 Strapi 5:介绍与常见问题 {#upgrading-to-strapi-5-introduction-and-faq} 🌐 Upgrading to Strapi 5: Introduction and FAQ Strapi 的最新主要版本是 Strapi 5。Strapi v4 仍将支持到 2026 年 4 月。 🌐 The latest major version of Strapi is Strapi 5. Strapi v4 is still supported until April 2026. 每当你准备好升级到 Strapi 5 时,本页面将为你提供帮助。它列出了从 Strapi 4 升级到 Strapi 5 的所有可用资源,并解答你可能有的一般问题。 🌐 Whenever you feel ready to upgrade to Strapi 5, the present page will help you. It lists all available resources for upgrading from Strapi 4 to Strapi 5 and answers general questions you might have. ## 可用资源 {#available-resources} 🌐 Available resources 以下所有可用资源将帮助你将应用和插件升级到 Strapi 5,从最常见到最具体的用例: 🌐 All of the following available resources will help you upgrade your application and plugins to Strapi 5, from the most common to the most specific use cases: ## 常见问题 {#frequently-asked-questions} 🌐 Frequently asked questions 以下问题及其答案应可帮助你涵盖最常见的用例: 🌐 The following questions and their answers should help you cover the most common use cases:
我该如何处理升级以及最新依赖的安装?
我该如何处理代码中的重大更改并将我的代码适配到 Strapi 5?
Strapi 提供了一个[升级工具](/cms/upgrade-tool)以简化此过程。该升级工具是一个命令行工具,带有一些处理依赖升级和执行 **codemods** 的命令。 按照 逐步指南 学习如何在升级到 Strapi 5 的情况下使用此工具。 Strapi 5 文档还提供了一个[完整的重大更改数据库](/cms/migration/v4-to-v5/breaking-changes)和[专用资源](/cms/migration/v4-to-v5/additional-resources/introduction)来覆盖特定的使用案例。
我如何处理数据迁移,以确保在 Strapi 5 中应用仍然能够正常工作?

Strapi 5 集成了一系列数据迁移脚本,这些脚本会在应用首次启动 Strapi 5 时运行。

但是,请 务必备份你的数据库 (如果使用 SQL 数据库,默认位置为 .tmp/data.db)在执行任何升级之前,如 逐步指南中所述。


作为 Strapi Cloud 的客户,我如何处理整个 Strapi 5 应用的升级和部署? 1. [创建备份](/cloud/projects/settings#backups) 并在本地更新你的代码,按照 逐步指南操作。 2. 从 [Cloud CLI](/cloud/cli/cloud-cli) 运行 `yarn deploy` 或 `npm run deploy` 命令。
Strapi Cloud 将在 Strapi 5 中部署更新的代码,并会自动运行数据迁移脚本。
在迁移过程中,我如何保持遗留的 attributes 封装器? - 对于 REST 客户端,在重构代码时添加 `Strapi-Response-Format: v4` 头。新的响应格式破坏性更改 ([new response format breaking change](/cms/migration/v4-to-v5/breaking-changes/new-response-format#migration)) 显示了在 `curl`、`fetch` 和 Axios 请求中添加该头的位置。 - 对于 GraphQL 客户端,启用 `v4CompatibilityMode` 并按照 [GraphQL API 迁移文档](/cms/migration/v4-to-v5/breaking-changes/graphql-api-updated#migration) 的步骤逐步移除 `attributes`。 - 当启用该头时,REST 响应仍会同时暴露 `id`(旧版)和 [`documentId`](/cms/migration/v4-to-v5/breaking-changes/use-document-id)。GraphQL 从不暴露数字 `id`,因此即使在关闭兼容模式之前,也请更新你的查询以使用 `documentId`。 一旦每个消费者读取了扁平化格式,移除头部,这样 Strapi 就会默认发出 Strapi 5 响应格式。
# 逐步升级到 Strapi 5 的指南 Source: https://docs.strapi.io/cms/migration/v4-to-v5/step-by-step # 逐步升级到 Strapi 5 的指南 {#step-by-step-guide-to-upgrade-to-strapi-5} 🌐 Step-by-step guide to upgrade to Strapi 5 Strapi 的最新主要版本是 Strapi 5。 🌐 The latest major version of Strapi is Strapi 5. 本页面旨在用作将 Strapi v4 应用升级到 Strapi 5 的分步说明。 🌐 The present page is meant to be used as step-by-step instructions for upgrading your Strapi v4 application to Strapi 5. :::prerequisites 你的 Strapi v4 应用已经在最新的 v4 小版本和修补版本上运行。如果没有,请使用 `minor` 命令运行 [升级工具](/cms/upgrade-tool) 以升级到最新版本:`npx @strapi/upgrade minor`。 🌐 Your Strapi v4 application is already running on the latest v4 minor and patch version. If it's not, run the [upgrade tool](/cms/upgrade-tool) with the `minor` command to reach it: `npx @strapi/upgrade minor`. ::: ## 步骤 1:准备升级 {#step-1-get-ready-to-upgrade} 🌐 Step 1: Get ready to upgrade 在进入升级过程之前,请采取以下预防措施: 🌐 Before getting into the upgrade process itself, take the following precautions: 1. **备份你的数据库**: * 如果你使用 SQLite 且采用默认配置(Strapi 提供的默认数据库),你的数据库文件名为 `data.db`,并位于 Strapi 应用根目录下的 `.tmp/` 文件夹中。 * 如果你使用的是其他类型的数据库,请参阅其官方文档(见 和 )。 * 如果你的项目托管在 Strapi Cloud 上,你可以手动[创建备份](/cloud/projects/settings#creating-a-manual-backup)。 2. **备份你的代码**: * 如果你的代码已使用 git 进行版本控制,请创建一个新的专用分支来运行迁移。 * 如果你的代码没有使用 git 进行版本控制,请创建你正在使用的 Strapi v4 代码的备份,并将其存放在安全的地方。 3. **确保你使用的插件与 Strapi 5 兼容**。 为此,请列出你正在使用的插件,然后通过阅读它们在 网站上的专用文档来检查每个插件的兼容性。 ## 步骤 2:运行自动迁移 {#step-2-run-automated-migrations} 🌐 Step 2: Run automated migrations Strapi 提供了一个工具来自动化升级到 Strapi 5 的某些部分:[升级工具](/cms/upgrade-tool)。 🌐 Strapi provides a tool to automate some parts of the upgrade to Strapi 5: the [upgrade tool](/cms/upgrade-tool). 1. **运行升级工具**。 ```sh npx @strapi/upgrade major ``` 该命令将执行 Strapi 5 依赖的更新和安装,并运行 codemods 来处理 Strapi 5 带来的一些重大更改。 codemods 将处理以下更改: | Codemod name and GitHub code link | Description | |-----------------------------------|-------------| | | Comment out lifecycles files in favor of [Document Service Middlewares](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service) | | | Remove the i18n plugin dependency as i18n is now integrated into the core of Strapi | | | Upgrade the react and react-dom dependencies | | | Upgrade the react-router-dom dependency | | | Upgrade the styled-components dependency | | | Partly handle migrations from `@strapi/helper-plugin` | | | Partly handle the migration from the Entity Service API to the new Document Service API | | | Wrap the `accessKeyId` and `secretAccessKey` properties inside a `credentials` object for users using the `aws-s3` provider | | | Update the sqlite dependency to better-sqlite3 | | | Transform `@strapi/strapi` imports to use the new public interface | | | Replace string dot format for config get/set/has with uid format for 'plugin' and 'api' namespace where possible | | | Update utils to use the new public interface | :::tip 如果你开发 Strapi 插件,其他代码修改工具会处理 helper-plugin 弃用的一些方面。有关更多信息,请参见[相关的重大更改](/cms/migration/v4-to-v5/breaking-changes/helper-plugin-deprecated)。 🌐 If you develop Strapi plugins, other codemods handle some aspects of the helper-plugin deprecation. See the [related breaking change](/cms/migration/v4-to-v5/breaking-changes/helper-plugin-deprecated) for more information. ::: 2. 查看升级工具所做的更改,以**检查是否需要手动完成某些代码更新**: 查找由 codemods 自动添加到你的代码中的 `__TODO__`。其中一些可能是在从 Entity Service API 迁移到 Strapi 5 引入的新 Document Service API 时添加的。 :::info Document Service API 关于文档服务 API 的更多信息可以在[重大更改条目说明](/cms/migration/v4-to-v5/breaking-changes/entity-service-deprecated)、[特定迁移指南](/cms/migration/v4-to-v5/additional-resources/from-entity-service-to-document-service)和[API 参考](/cms/api/document-service)中找到。 ::: ## 步骤 3:检查并处理手动升级 {#step-3-check-and-handle-manual-upgrades} 🌐 Step 3: Check and handle manual upgrades 以下主要更改可能会影响你的 Strapi 应用并要求你执行一些手动操作。 🌐 The following main changes might affect your Strapi application and require you to do some manual actions. 对于每个日志项,请阅读指示的重大更改条目并检查升级工具运行后是否仍需要某些手动操作: 🌐 For each of them, read the indicated breaking change entry and check if some manual actions are still required after the upgrade tool has run: 1. **数据库迁移**: 1. 不支持 MySQL v5 👉 查看 [重大变更](/cms/migration/v4-to-v5/breaking-changes/mysql5-unsupported) 2. 仅支持 better-sqlite3 👉 参见 [breaking change](/cms/migration/v4-to-v5/breaking-changes/only-better-sqlite3-for-sqlite) 3. 只支持 mysql2 👉 参见 [重大更改](/cms/migration/v4-to-v5/breaking-changes/only-mysql2-package-for-mysql) 4. 生命周期钩子的触发方式有所不同 👉 请参见 [重大更改](/cms/migration/v4-to-v5/breaking-changes/lifecycle-hooks-document-service) 2. **配置**: 1. 一些环境变量由服务器配置处理 👉 参见 [重大更改](/cms/migration/v4-to-v5/breaking-changes/removed-support-for-some-env-options) 2. 自定义配置必须满足特定要求 👉 请参见 [重大更改](/cms/migration/v4-to-v5/breaking-changes/strict-requirements-config-files) 3. **管理面板自定义**: * 助手插件已被移除 👉 参见 [迁移参考](/cms/migration/v4-to-v5/additional-resources/helper-plugin) 👉 最后,查看剩余的 [breaking changes 数据库](/cms/migration/v4-to-v5/breaking-changes),以了解你可能关心的任何边缘情况。 ## 步骤 4:迁移API消费端 {#step-4-migrate-the-api-consuming-side} 🌐 Step 4: Migrate the API consuming side Strapi 5 已更新 REST 和 GraphQL API。 🌐 Strapi 5 has updated both the REST and GraphQL APIs. 请按照以下步骤操作,并利用向后兼容性标头和引导式迁移资源,逐步将你的代码更新为 Strapi 5。 🌐 Follow the steps below and leverage retro-compatibility headers and guided migration resources to gradually update your code for Strapi 5. ### 迁移 REST API 调用 {#migrate-rest-api-calls} 🌐 Migrate REST API calls 1. 通过在 HTTP 客户端、SDK 和中间件的 REST 调用中添加 `Strapi-Response-Format: v4`,在所有仍然期望使用 `attributes` 的地方启用兼容性头(具体示例请参见[重大更改条目](/cms/migration/v4-to-v5/breaking-changes/new-response-format#migration))。 2. 在启用头部的同时,审计现有的有效负载。捕获有代表性的响应(包括已填充的关系、组件和媒体),以便在过渡期间验证旧版使用者仍能正常工作。 3. 通过以下方式更新和测试每个客户端: - 移除 `data.attributes` 访问权限, - 切换到扁平化有效负载后, - 并在以前 REST API 仅返回数字 `id` 的地方采用 [`documentId`](/cms/migration/v4-to-v5/breaking-changes/use-document-id)。 4. 针对每个端点或消费者禁用兼容性头:一旦某个客户端的测试通过,从其请求中移除 `Strapi-Response-Format: v4`。重复此操作,直到没有消费者依赖旧封装器。 ### 迁移 GraphQL API 调用 {#migrate-graphql-api-calls} 🌐 Migrate GraphQL API calls 1. 通过在 `graphql` 插件配置中将 `v4CompatibilityMode` 设置为 `true` 来启用兼容性头,以便客户端在你重构它们时可以继续依赖 `data.attributes`。 2. 按照 [GraphQL 的重大变更条目](/cms/migration/v4-to-v5/breaking-changes/graphql-api-updated) 的每一步操作。这将指导你用 `documentId` 替换 `id`,采用 `_connection` 查询,移除 `attributes`,并最终切换到 `nodes/pageInfo`。 3. 通过确认在为不需要 Relay 语义的客户端移除 `_connection` 和 `data` 时分页元数据仍然符合预期,测试 Relay 和非 Relay 查询。 4. 禁用 `v4CompatibilityMode` 兼容性头:在每个查询和变更都能使用扁平化模式后,将头设置为 `false`,以便服务器默认输出 Strapi 5 格式。 # 管理员钩子 Source: https://docs.strapi.io/cms/plugins-development/admin-hooks # 管理面板 API:钩子 {#admin-panel-api-hooks} 🌐 Admin Panel API: Hooks Hooks API 允许插件创建和注册钩子,即应用中插件可以添加个性化行为的位置。 🌐 The Hooks API allows a plugin to create and register hooks, i.e. places in the application where plugins can add personalized behavior. :::note 为了插件之间可预测的互操作性,请使用稳定的命名空间钩子 ID,例如 `my-plugin/my-hook`。 🌐 For predictable interoperability between plugins, use stable namespaced hook IDs such as `my-plugin/my-hook`. ::: ## 订阅钩子 {#subscribing-to-hooks} 🌐 Subscribing to hooks 在所有插件加载完成后,在[`bootstrap`](/cms/plugins-development/admin-panel-api#bootstrap)生命周期中使用`registerHook()`订阅钩子。回调函数会接收来自钩子调用者的参数,并应返回(可选修改的)数据。 🌐 Subscribe to hooks with `registerHook()` during the [`bootstrap`](/cms/plugins-development/admin-panel-api#bootstrap) lifecycle, once all plugins are loaded. The callback receives arguments from the hook caller and should return the (optionally mutated) data. 异步回调也被支持: 🌐 Async callbacks are also supported: ## 运行钩子 {#running-hooks} 🌐 Running hooks 钩子可以在三种模式下运行: 🌐 Hooks can be run in 3 modes: | 模式 | 功能 | 返回值 ||---|---|---|| 串行 | `runHookSeries` | 每个函数的结果数组,按顺序 || 并行 | `runHookParallel` | 已解决的 Promise 结果数组,按顺序 || 瀑布 | `runHookWaterfall` | 应用所有转换后得到的单个值 | :::caution 对于 `runHookWaterfall`,每个订阅者必须返回转换后的值,以便链中的下一个订阅者接收它。不返回值将会打断链。 🌐 For `runHookWaterfall`, each subscriber must return the transformed value so that the next subscriber in the chain receives it. Failing to return a value will break the chain. ::: ## 使用预定义的钩子 {#using-predefined-hooks} 🌐 Using predefined hooks Strapi 包含为内容管理器的列表和编辑视图预定义的钩子。 🌐 Strapi includes predefined hooks for the Content Manager's List and Edit views. ### `INJECT-COLUMN-IN-TABLE` `Admin/CM/pages/ListView/inject-column-in-table` 钩子可以在 [内容管理器](/cms/intro) 的列表视图中添加或修改列: 🌐 The `Admin/CM/pages/ListView/inject-column-in-table` hook can add or mutate columns in the List View of the [Content Manager](/cms/intro): ```tsx runHookWaterfall(INJECT_COLUMN_IN_TABLE, { displayedHeaders: ListFieldLayout[], layout: ListFieldLayout, }); ``` 以下示例订阅此钩子以添加自定义“外部 ID”列: 🌐 The following example subscribes to this hook to add a custom "External id" column: **ListFieldLayout 和 ListLayout 类型定义**: ### `MUTATE-EDIT-VIEW-LAYOUT` `Admin/CM/pages/EditView/mutate-edit-view-layout` 钩子可以修改 [内容管理器](/cms/intro) 的编辑视图布局。 🌐 The `Admin/CM/pages/EditView/mutate-edit-view-layout` hook can mutate the Edit View layout of the [Content Manager](/cms/intro). 下面的示例订阅这个钩子以将所有字段强制为全宽: 🌐 The following example subscribes to this hook to force all fields to full width: **EditLayout 和 EditFieldLayout 类型定义:** :::note 此处记录的 `EditLayout` 和 `ListLayout` 形状来自 `useDocumentLayout` 钩子(参见 )。内部包命名可能有所不同,但插件作者应依赖本页中公开的 `EditLayout` 和 `ListLayout` 形状。 ::: # 管理员注入区 Source: https://docs.strapi.io/cms/plugins-development/admin-injection-zones # 管理面板 API:注入区域 {#admin-panel-api-injection-zones} 🌐 Admin Panel API: Injection zones 插件可以通过将自定义 React 组件注入预定义区域来扩展和自定义现有的管理面板部分。这使你能够在不修改核心代码的情况下,为 Strapi 的内置界面添加功能。 🌐 Plugins can extend and customize existing admin panel sections by injecting custom React components into predefined areas. This allows you to add functionality to Strapi's built-in interfaces without modifying core code. ## 自定义注入区域 {#custom-injection-zones} 🌐 Custom injection zones 插件可以定义自己的注入区域,以允许其他插件扩展它们的用户界面。在 `registerPlugin` 配置中声明注入区域: 🌐 Plugins can define their own injection zones to allow other plugins to extend their UI. Declare injection zones in the `registerPlugin` configuration: ### 在组件中呈现注入区域 {#rendering-injection-zones-in-components} 🌐 Rendering injection zones in components 在 Strapi 5 中,来自 `@strapi/helper-plugin` 的 `InjectionZone` 组件已被移除,且没有直接的替代导出。要渲染注入的组件,请使用来自 `@strapi/strapi/admin` 的 `useStrapiApp` 创建你自己的组件。 🌐 In Strapi 5, the `InjectionZone` component from `@strapi/helper-plugin` is removed and has no direct replacement export. To render injected components, create your own component with `useStrapiApp` from `@strapi/strapi/admin`. ### 注入自定义区域 {#injecting-into-custom-zones} 🌐 Injecting into custom zones 其他插件可以使用它们 `bootstrap` 生命周期中的 `injectComponent()` 方法将组件注入到你的自定义注入区域: 🌐 Other plugins can inject components into your custom injection zones using the `injectComponent()` method in their `bootstrap` lifecycle: ## 喷射组件参数 {#injection-component-parameters} 🌐 Injection component parameters `injectComponent()` 方法接受以下参数: 🌐 The `injectComponent()` method accepts the following parameters: | 参数 | 类型 | 描述 ||---|---|---|| `view` | `string` | 组件应该被注入的视图名称 || `zone` | `string` | 视图中组件应该被注入的区域名称 || `component` | `object` | 配置对象,包含 `name`(唯一字符串)和 `Component`(要注入的 React 组件) | ## 内容经理数据访问 {#content-manager-data-access} 🌐 Content Manager data access 在将组件注入内容管理器注入区域时,你可以使用 `useContentManagerContext` 钩子访问编辑视图数据: 🌐 When injecting components into Content Manager injection zones, you can access the Edit View data using the `useContentManagerContext` hook: :::caution `useContentManagerContext` 钩子目前以 `unstable_useContentManagerContext` 导出。`unstable_` 前缀表示该 API 在未来版本中可能会发生变化。该钩子替代了来自 `@strapi/helper-plugin` 的已弃用 `[useCMEditViewDataManager](/cms/migration/v4-to-v5/additional-resources/helper-plugin#usecmeditviewdatamanager)`,该钩子在 Strapi 5 中不可用。 🌐 The `useContentManagerContext` hook is currently exported as `unstable_useContentManagerContext`. The `unstable_` prefix indicates the API may change in future releases. This hook replaces the [deprecated `useCMEditViewDataManager`](/cms/migration/v4-to-v5/additional-resources/helper-plugin#usecmeditviewdatamanager) from `@strapi/helper-plugin` which is not available in Strapi 5. ::: ## 最佳实践 {#best-practices} 🌐 Best practices - **使用描述性的区域名称。** 为你的注入区域选择清晰的名称(例如,`top`、`bottom`、`before`、`after`)。 - **检查插件可用性。** 在将组件注入插件的区域之前,请始终确认该插件是否存在: ```js bootstrap(app) { const targetPlugin = app.getPlugin('target-plugin'); if (targetPlugin) { targetPlugin.injectComponent('view', 'zone', { name: 'my-component', Component: MyComponent, }); } } ``` - **使用唯一的组件名称。** 确保组件名称是唯一的,以避免与其他插件发生冲突。 - **优雅地处理缺失的区域。** 组件应处理注入区域可能不可用的情况。 - **记录你的注入区域。** 清晰地记录你的插件提供了哪些注入区域以及它们的预期用途。 # 管理员本地化 Source: https://docs.strapi.io/cms/plugins-development/admin-localization # 管理面板 API:本地化 {#admin-panel-api-localization} 🌐 Admin Panel API: Localization 插件可以为多种语言提供翻译,使管理界面对全球用户可访问。Strapi 会自动加载并合并插件翻译与核心翻译,使它们在整个管理面板中可用。 🌐 Plugins can provide translations for multiple languages to make the admin interface accessible to users worldwide. Strapi automatically loads and merges plugin translations with core translations, making them available throughout the admin panel. ### 函数参数 {#function-parameters} 🌐 Function parameters `registerTrads` 函数接收一个具有以下属性的对象: 🌐 The `registerTrads` function receives an object with the following property: | 参数 | 类型 | 描述 ||---|---|---|| `locales` | `string[]` | 在管理面板中配置的区域设置代码数组(例如,`['en', 'fr', 'de']`) | ### 返回值 {#return-value} 🌐 Return value 该函数必须返回一个 `Promise`,该 `Promise` 解析为翻译对象数组。每个对象具有以下结构: 🌐 The function must return a `Promise` that resolves to an array of translation objects. Each object has the following structure: ```ts { data: Record; // Translation key-value pairs locale: string; // Locale code (e.g., 'en', 'fr') } ``` ### 翻译键前缀 {#translation-key-prefixing} 🌐 Translation key prefixing :::caution 翻译键必须以你的插件 ID 为前缀,以避免与其他插件和 Strapi 核心翻译的冲突。例如,如果你的插件 ID 是 `my-plugin`,那么像 `plugin.name` 这样的键应该变为 `my-plugin.plugin.name`。 🌐 Translation keys must be prefixed with your plugin ID to avoid conflicts with other plugins and core Strapi translations. For example, if your plugin ID is `my-plugin`, a key like `plugin.name` should become `my-plugin.plugin.name`. ::: 使用 `prefixPluginTranslations` 工具函数自动为所有键添加前缀: 🌐 Use the `prefixPluginTranslations` utility function to automatically prefix all keys: 例如,如果你的翻译文件包含: 🌐 For instance, if your translation file contains: ```json { "plugin.name": "My Plugin", "settings.title": "Settings" } ``` 在前缀添加插件 ID `my-plugin` 后,这些变为: 🌐 After prefixing with plugin ID `my-plugin`, these become: - `my-plugin.plugin.name` - `my-plugin.settings.title` ### 缺少翻译文件 {#missing-translation-files} 🌐 Missing translation files `registerTrads` 函数应该通过为该语言环境返回一个空对象来优雅地处理缺失的翻译文件。上面的示例中的 `.catch()` 处理程序确保即使翻译文件不存在,插件仍然返回一个有效的翻译对象: 🌐 The `registerTrads` function should gracefully handle missing translation files by returning an empty object for that locale. The `.catch()` handler in the example above ensures that if a translation file does not exist, the plugin still returns a valid translation object: ```js .catch(() => { return { data: {}, locale, }; }); ``` 这允许插件只为某些语言环境提供翻译(例如,仅英语),而不会破坏其他语言环境的管理面板。 🌐 This allows plugins to provide translations for only some locales (e.g., only English) without breaking the admin panel for other locales. ## 组件中的翻译 {#translations-in-components} 🌐 Translations in components 要在你的 React 组件中使用翻译,请使用来自 `react-intl` 的 `useIntl` 钩子: 🌐 To use translations in your React components, use the `useIntl` hook from `react-intl`: ### 翻译键的辅助函数 {#helper-function-for-translation-keys} 🌐 Helper function for translation keys 为了避免重复插件 ID 前缀,请创建一个辅助函数: 🌐 To avoid repeating the plugin ID prefix, create a helper function: 然后在组件中使用它: 🌐 Then use it in components: ## 配置中的翻译 {#translations-in-configuration} 🌐 Translations in configuration 在配置菜单链接、设置部分以及其他管理面板元素时,也会使用翻译键: 🌐 Translation keys are also used when configuring menu links, settings sections, and other admin panel elements: ## 插件翻译生命周期 {#plugin-translation-lifecycle} 🌐 Plugin translation lifecycle Strapi 的管理面板自动: 🌐 Strapi's admin panel automatically: 1. 在初始化期间调用所有已注册插件的 `registerTrads` 2. 将所有插件的翻译与核心 Strapi 翻译合并 3. 应用管理员配置的自定义翻译(如果有的话) 4. 通过 `react-intl` 在整个管理面板中提供翻译 在实际操作中,核心管理翻译首先加载,插件翻译会在其上合并,而 `config.translations` 中的项目级覆盖允许你自定义在管理面板中显示的标签。 🌐 In practice, core admin translations are loaded first, plugin translations are merged on top, and project-level overrides in `config.translations` let you customize the labels displayed in the admin panel. ## 最佳实践 {#best-practices} 🌐 Best practices - **始终为翻译键添加前缀。** 使用 `prefixPluginTranslations` 或手动为键添加你的插件 ID 作为前缀以避免冲突。 - **提供默认消息。** 如果翻译缺失,使用 `formatMessage` 作为回退时,请始终包含 `defaultMessage`。 - **优雅地处理缺失的翻译。** `registerTrads` 函数对于缺失的语言环境应返回空对象,而不是抛出错误。 - **使用描述性键名。** 选择清晰、有层次的键名(例如,`settings.general.title` 而不是 `title1`)。 - **至少支持英语。** 提供英文翻译可以确保你的插件开箱即可使用。 - **验证多种语言环境下的行为。** 测试当在管理面板中选择不同的语言环境时,你的插件是否能正常工作。 :::note `en` 语言环境在 Strapi 中始终可用,并作为备用语言环境。如果所选语言环境缺少翻译,Strapi 会使用英文翻译。 🌐 The `en` locale is always available in Strapi and serves as the fallback locale. If a translation is missing for a selected locale, Strapi uses the English translation. ::: :::tip 要查看你的 Strapi 实例中可用的语言环境,请检查 `src/admin/app.ts` 或 `src/admin/app.js` 文件中的 `config.locales` 数组。要在运行时以编程方式访问,请参阅 [访问 Redux 存储](/cms/plugins-development/admin-redux-store)(注意内部存储结构可能会随着版本变化而改变)。 🌐 To see which locales are available in your Strapi instance, check the `config.locales` array in your `src/admin/app.ts` or `src/admin/app.js` file. For programmatic access at runtime, see [Accessing the Redux store](/cms/plugins-development/admin-redux-store) (note that internal store structure may change between versions). ::: # 管理员导航与设置 Source: https://docs.strapi.io/cms/plugins-development/admin-navigation-settings # 管理面板 API:导航与设置 {#admin-panel-api-navigation--settings} 🌐 Admin Panel API: Navigation & settings 插件可以自定义管理员面板的导航侧边栏和设置页面,以提供对其功能的访问。本文所述的所有功能都是在插件入口文件的 [`register`](/cms/plugins-development/admin-panel-api#register) 或 [`bootstrap`](/cms/plugins-development/admin-panel-api#bootstrap) 生命周期函数中调用的。 🌐 Plugins can customize the admin panel's navigation sidebar and settings pages to provide access to their features. All functions described on this page are called within the [`register`](/cms/plugins-development/admin-panel-api#register) or [`bootstrap`](/cms/plugins-development/admin-panel-api#bootstrap) lifecycle functions of your plugin's entry file. ## 设置 {#settings} 🌐 Settings 设置 API 允许插件创建新的设置部分或向现有部分添加链接。设置部分是组织好的配置页面组,可以从导航侧边栏的 `createSettingSection()` 函数接受以下参数: 🌐 The `createSettingSection()` function accepts the following parameters: * 第一个参数是部分配置: | 参数 | 类型 | 必填 | 描述 | |---|---|---|---| | `id` | `string` | ✅ | 设置部分的唯一标识符 | | `intlLabel` | `object` | ✅ | 部分的本地化标签,遵循 `addSettingsLink` 和 `addSettingsLinks` 都将 `sectionId` 字符串作为第一个参数(例如,`'global'` 或 `'permissions'`)。第二个参数对于 `addSettingsLink` 是单个链接对象,对于 `addSettingsLinks` 是链接对象数组,使用与 [`createSettingSection()`(见上表)](#creating-a-new-settings-section) 中的 `links` 数组相同的属性。 ### 可用的设置部分 {#available-settings-sections} 🌐 Available settings sections Strapi 提供了内置的设置部分,插件可以扩展这些部分: 🌐 Strapi provides built-in settings sections that plugins can extend: - `global`:通用应用设置 - `permissions`:管理面板设置 :::note 创建新的设置部分必须在 `register` 生命周期函数中完成。向现有设置部分添加链接必须在 `bootstrap` 生命周期函数中完成。 🌐 Creating a new settings section must be done in the `register` lifecycle function. Adding links to existing settings sections must be done in the `bootstrap` lifecycle function. ::: ### `to` 的路径约定 {#path-conventions-for-to} 🌐 Path conventions for `to` `to` 参数的行为取决于上下文: 🌐 The `to` parameter behaves differently depending on the context: | 上下文 | `to` 值 | 最终网址 ||---|---|---|| `addMenuLink` | `/plugins/my-plugin` | `http://localhost:1337/admin/plugins/my-plugin` || `createSettingSection` 链接 | `my-plugin/general` | `http://localhost:1337/admin/settings/my-plugin/general` || `addSettingsLink` | `my-plugin/documentation` | `http://localhost:1337/admin/settings/my-plugin/documentation` | 对于菜单链接,路径是相对于管理面板根目录(`/admin`)。对于设置链接,路径是相对于设置路由(`/admin/settings`)。在设置链接路径中不要包含 `settings/` 前缀。 🌐 For menu links, the path is relative to the admin panel root (`/admin`). For settings links, the path is relative to the settings route (`/admin/settings`). Do not include the `settings/` prefix in settings link paths. :::strapi Securing plugin routes 链接上的 `permissions` 参数仅控制在导航中的可见性。要完全保护你的插件页面并注册 RBAC 操作,请参阅 [插件的管理员权限](/cms/plugins-development/guides/admin-permissions-for-plugins) 指南。 🌐 The `permissions` parameter on links only controls visibility in the navigation. To fully protect your plugin pages and register RBAC actions, see the [Admin permissions for plugins](/cms/plugins-development/guides/admin-permissions-for-plugins) guide. ::: # 管理面板 API 概述 Source: https://docs.strapi.io/cms/plugins-development/admin-panel-api # 插件的管理面板 API 概述 {#admin-panel-api-for-plugins-an-overview} 🌐 Admin Panel API for plugins: An overview Strapi 插件可以与 Strapi 应用的后端和前端进行交互。管理面板 API 涵盖了前端部分:它允许插件自定义 Strapi 的[管理面板](/cms/intro)。管理面板是一个 #### registerPlugin() {#registerplugin} **类型:** `Function` 注册插件以使其在管理面板中可用。此函数在[`register()`](#register)生命周期函数中被调用,并返回一个包含以下参数的对象: 🌐 Registers the plugin to make it available in the admin panel. This function is called within the [`register()`](#register) lifecycle function and returns an object with the following parameters: | 参数 | 类型 | 描述 || --- | --- | --- || `id` | 字符串 | 插件 ID || `name` | 字符串 | 插件名称 || `apis` | `Record` | 向其他插件开放的 API || `initializer` | `React.ComponentType` | 插件初始化的组件 || `injectionZones` | 对象 | 可用 [注入区域](/cms/plugins-development/admin-injection-zones) 的声明 || `isReady` | 布尔值 | 插件就绪状态(默认值:`true`) | :::note 一些参数可以从 `package.json` 文件中导入。 🌐 Some parameters can be imported from the `package.json` file. ::: **示例:** ### bootstrap() {#bootstrap} **类型**: `Function` 暴露 bootstrap 函数,在所有插件[注册](#register)之后执行。 🌐 Exposes the bootstrap function, executed after all the plugins are [registered](#register). 在 `bootstrap()` 函数中,插件可以: 🌐 Within the `bootstrap()` function, a plugin can: * 使用 `getPlugin('plugin-name')` 扩展另一个插件, * 注册钩子(参见 [Hooks](/cms/plugins-development/admin-hooks)), * [添加到设置部分的链接](/cms/plugins-development/admin-navigation-settings#adding-links-to-existing-settings-sections), * 在内容管理器的列表视图和编辑视图中添加操作和选项(参见 [内容管理器 API](/cms/plugins-development/content-manager-apis))。 **示例:** ## 可用操作 {#available-actions} 🌐 Available actions 管理面板 API 提供了多个构建模块,用于自定义管理面板的用户界面、用户体验和行为。 🌐 The Admin Panel API provides several building blocks to customize the user interface, user experience, and behavior of the admin panel. 使用下表查找要使用的函数以及在哪里声明它。点击任意函数名称以获取详细信息: 🌐 Use the following table to find which function to use and where to declare it. Click any function name for details: | 操作 | 使用的函数 | 相关的生命周期函数 | | --- | --- | --- | | 在主导航中添加新链接 | [`addMenuLink()`](/cms/plugins-development/admin-navigation-settings#navigation-sidebar-menu-links) | [`register()`](#register) | | 创建一个新的设置部分 | [`createSettingSection()`](/cms/plugins-development/admin-navigation-settings#creating-a-new-settings-section) | [`register()`](#register) | | 添加一个到设置部分的单一链接 | [`addSettingsLink()`](/cms/plugins-development/admin-navigation-settings#adding-links-to-existing-settings-sections) | [`bootstrap()`](#bootstrap) | | 在设置部分添加多个链接 | [`addSettingsLinks()`](/cms/plugins-development/admin-navigation-settings#adding-links-to-existing-settings-sections) | [`bootstrap()`](#bootstrap) | | 在内容管理器的编辑视图和列表视图中添加面板、选项和操作 |
  • [`addEditViewSidePanel()`](/cms/plugins-development/content-manager-apis#addeditviewsidepanel)
  • [`addDocumentAction()`](/cms/plugins-development/content-manager-apis#adddocumentaction)
  • [`addDocumentHeaderAction()`](/cms/plugins-development/content-manager-apis#adddocumentheaderaction)
  • [`addBulkAction()`](/cms/plugins-development/content-manager-apis#addbulkaction)
| [`bootstrap()`](#bootstrap) | | 声明注入区 | [`registerPlugin()`](#registerplugin) | [`register()`](#register) | | 在注入区域注入组件 | [`injectComponent()`](/cms/plugins-development/admin-injection-zones) | [`bootstrap()`](#bootstrap) | | 添加一个 reducer | [`addReducers()`](/cms/plugins-development/admin-redux-store#adding-custom-reducers) | [`register()`](#register) | | 创建一个钩子 | [`createHook()`](/cms/plugins-development/admin-hooks) | [`register()`](#register) | | 注册一个钩子 | [`registerHook()`](/cms/plugins-development/admin-hooks) | [`bootstrap()`](#bootstrap) | | 为插件管理界面提供翻译 | [`registerTrads()`](/cms/plugins-development/admin-localization#registertrads) | `registerTrads()` |
点击以下任意卡片以获取有关特定主题的更多详细信息: :::tip Replacing the WYSIWYG 可以通过利用[自定义字段](/cms/features/custom-fields)来替换所见即所得编辑器,例如使用 。 🌐 The WYSIWYG editor can be replaced by taking advantage of [custom fields](/cms/features/custom-fields), for instance using the . ::: :::info 管理面板支持 dotenv 变量。 🌐 The admin panel supports dotenv variables. 所有在 `.env` 文件中定义并以 `STRAPI_ADMIN_` 为前缀的变量,在通过 `process.env` 自定义管理面板时都是可用的。 🌐 All variables defined in a `.env` file and prefixed by `STRAPI_ADMIN_` are available while customizing the admin panel through `process.env`. ::: # Redux 存储和 reducers Source: https://docs.strapi.io/cms/plugins-development/admin-redux-store # 管理面板 API:Redux 存储与 reducers {#admin-panel-api-redux-store--reducers} 🌐 Admin Panel API: Redux store & reducers Strapi 的管理面板使用全局 Redux 存储来管理应用状态。插件可以访问此存储以读取状态、分发动作以及订阅状态变化。这使得插件能够与核心管理功能进行交互,例如主题设置、语言偏好和身份验证状态。 🌐 Strapi's admin panel uses a global Redux store to manage application state. Plugins can access this store to read state, dispatch actions, and subscribe to state changes. This enables plugins to interact with core admin functionality like theme settings, language preferences, and authentication state. ## 使用 `useSelector` 读取状态 {#reading-state-with-useselector} 🌐 Reading state with `useSelector` 在你的插件组件中访问 Redux 状态最常见的方式是使用来自 `react-redux` 的 `useSelector` 钩子: 🌐 The most common way to access Redux state in your plugin components is using the `useSelector` hook from `react-redux`: ### 可用状态属性 {#available-state-properties} 🌐 Available state properties `admin_app` 切片包含以下状态属性: 🌐 The `admin_app` slice contains the following state properties: | 属性 | 类型 | 描述 ||---|---|---|| `theme.currentTheme` | `string` | 当前主题 (`'light'`、`'dark'` 或 `'system'`) || `theme.availableThemes` | `string[]` | 可用主题名称数组 || `language.locale` | `string` | 当前语言代码(例如,`'en'`、`'fr'`) || `language.localeNames` | `object` | 将语言代码映射到显示名称的对象 || `token` | `string \| null` | 认证令牌 || `permissions` | `object` | 用户权限对象 | ## 派发动作 {#dispatching-actions} 🌐 Dispatching actions 要更新 Redux 存储,请使用 `useDispatch` 钩子: 🌐 To update the Redux store, use the `useDispatch` hook: :::note 下面的示例为了说明用途,将操作分发到核心管理状态(主题、语言环境)。在实际操作中,大多数插件应将操作分发到它们自己的自定义 reducer,而不是修改全局管理状态。 🌐 The examples below dispatch actions to core admin state (theme, locale) for illustration purposes. In practice, most plugins should dispatch actions to their own custom reducers rather than modifying global admin state. ::: ### 可用操作 {#available-actions} 🌐 Available actions `admin_app` 切片提供以下操作: 🌐 The `admin_app` slice provides the following actions: | 操作类型 | 载荷类型 | 描述 ||---|---|---|| `admin/setAppTheme` | `string` | 设置主题(`'light'`、`'dark'` 或 `'system'`) || `admin/setAvailableThemes` | `string[]` | 更新 `admin_app` 中的 `theme.availableThemes` || `admin/setLocale` | `string` | 设置语言环境(例如 `'en'`、`'fr'`) || `admin/setToken` | `string \| null` | 设置认证令牌 || `admin/login` | `{ token: string, persist?: boolean }` | 使用令牌和持久化选项的登录操作 || `admin/logout` | `void` | 登出操作(无载荷) | :::note 在分发操作时,使用 Redux Toolkit 操作类型格式:`'sliceName/actionName'`。管理员切片名为 `'admin'`,因此操作遵循模式 `'admin/actionName'`。 🌐 When dispatching actions, use the Redux Toolkit action type format: `'sliceName/actionName'`. The admin slice is named `'admin'`, so actions follow the pattern `'admin/actionName'`. ::: ## 访问存储实例 {#accessing-the-store-instance} 🌐 Accessing the store instance 对于高级用例,你可以使用 `useStore` 钩子直接访问存储实例: 🌐 For advanced use cases, you can access the store instance directly using the `useStore` hook: ## 完整示例 {#complete-example} 🌐 Complete example 以下示例结合了本页描述的所有三种模式(useSelector、useDispatch、useStore): 🌐 The following example combines all 3 patterns (useSelector, useDispatch, useStore) described on the present page: {Object.keys(availableLocales).map((locale) => ( ))} {lastChange && ( )} ); }; ```
{Object.keys(availableLocales).map((locale) => ( ))} {lastChange && ( )} ); }; ```
## 最佳实践 {#best-practices} 🌐 Best practices - **使用 `useSelector` 来读取状态。** 相较于直接访问 store,更推荐使用 [`useSelector`](#reading-state-with-useselector)。它会自动订阅更新,并在所选状态变化时重新渲染组件。 - **清理订阅。** 始终在 `useEffect` 清理函数中取消订阅存储订阅,以防止内存泄漏。 - **考虑类型安全。** 在插件中访问 Redux 状态时,使用带有插件本地类型的 `react-redux` 钩子(例如 `useSelector`、`useDispatch`)(例如 `RootState` 和 `AppDispatch`)。如果使用 Strapi 管理工具,请从 `@strapi/admin/strapi-admin` 导入它们(而不是 `@strapi/admin`)。在它们明确被记录为稳定之前,避免依赖未记录的带类型的 Redux 钩子作为 Strapi 的公共 API。 - **避免不必要的分发。** 只有在需要更新状态时才分发操作。读取状态不需要分发操作。 - **尊重核心状态。** 修改核心管理状态(如主题或语言环境)时要小心,因为这会影响整个管理面板。请考虑你的插件是否应该修改全局状态,还是保持自己的本地状态。 :::tip 要将你自己的状态添加到 Redux 存储中,请参阅上面的 [添加自定义 reducer](#adding-custom-reducers)。 🌐 To add your own state to the Redux store, see [Adding custom reducers](#adding-custom-reducers) above. ::: # 内容管理器 API Source: https://docs.strapi.io/cms/plugins-development/content-manager-apis # 内容管理器 API {#content-manager-apis} 🌐 Content Manager APIs 内容管理器 API 是 [管理面板 API](/cms/plugins-development/admin-panel-api) 的一部分。它们是 Strapi 插件向 [内容管理器](/cms/features/content-manager) 添加内容或选项的一种方式。内容管理器 API 允许你通过添加来自你自己插件的功能来扩展内容管理器,就像你可以通过 [注入区域](/cms/plugins-development/admin-injection-zones) 所做的一样。 🌐 Content Manager APIs are part of the [Admin Panel API](/cms/plugins-development/admin-panel-api). They are a way for Strapi plugins to add content or options to the [Content Manager](/cms/features/content-manager). The Content Manager APIs allow you to extend the Content Manager by adding functionality from your own plugin, just like you can do it with [Injection zones](/cms/plugins-development/admin-injection-zones). - 传递一个接收当前元素并返回新元素的函数。这很有用,例如,如果你想在列表中的特定位置添加某些内容,就像下面的代码一样: ### 组件 {#components} 🌐 Components 你需要将组件传递给 API 才能将内容添加到内容管理器。 🌐 You need to pass components to the API in order to add things to the Content Manager. 组件是接收一些属性并返回具有某种形状对象的函数(取决于函数本身)。每个组件返回的对象根据你使用的函数不同而不同,但它们接收的属性相似,这取决于你使用的是 ListView 还是 EditView API。 🌐 Components are functions that receive some properties and return an object with some shape (depending on the function). Each component's return object is different based on the function you're using, but they receive similar properties, depending on whether you use a ListView or EditView API. 属性包括有关你正在查看或编辑的文档的重要信息。 🌐 Properties include important information about the document(s) you are viewing or editing. #### ListViewContext ```jsx interface ListViewContext { /** * Will be either 'single-types' | 'collection-types' */ collectionType: string; /** * The current selected documents in the table */ documents: Document[]; /** * The current content-type's model. */ model: string; } ``` #### EditViewContext ```jsx interface EditViewContext { /** * This will only be null if the content-type * does not have draft & publish enabled. */ activeTab: 'draft' | 'published' | null; /** * Will be either 'single-types' | 'collection-types' */ collectionType: string; /** * Will be undefined if someone is creating an entry. */ document?: Document; /** * Will be undefined if someone is creating an entry. */ documentId?: string; /** * Will be undefined if someone is creating an entry. */ meta?: DocumentMetadata; /** * The current content-type's model. */ model: string; } ``` :::tip 有关类型和 API 的更多信息可以在 ## 可用的 API {#available-apis} 🌐 Available APIs
### `addEditViewSidePanel` 使用此功能可将新面板添加到“编辑”视图侧边栏,就像以下示例中将某些内容添加到“发布”面板一样: 🌐 Use this to add new panels to the Edit view sidebar, just like in the following example where something is added to the Releases panel: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-edit-view-side-panel.png) ```jsx addEditViewSidePanel(panels: DescriptionReducer | PanelComponent[]) ``` #### PanelComponent 一个 `PanelComponent` 接收在 [EditViewContext](#editviewcontext) 中列出的属性,并返回具有以下结构的对象: 🌐 A `PanelComponent` receives the properties listed in [EditViewContext](#editviewcontext) and returns an object with the following shape: ```tsx type PanelComponent = (props: PanelComponentProps) => { title: string; content: React.ReactNode; }; ``` `PanelComponentProps` 扩展了 [EditViewContext](#editviewcontext)。 ### `addDocumentAction` 使用此 API 可向内容管理器的编辑视图或列表视图添加更多操作。共有3个可用位置: 🌐 Use this API to add more actions to the Edit view or the List View of the Content Manager. There are 3 positions available: - 编辑视图的 `header`: ![编辑视图的标题](/img/assets/content-manager-apis/add-document-action-header.png) - 编辑视图的 `panel`: ![编辑视图面板](/img/assets/content-manager-apis/add-document-action-panel.png) - 列表视图的 `table-row`: ![列表视图中的表格行](/img/assets/content-manager-apis/add-document-action-tablerow.png) ```jsx addDocumentAction(actions: DescriptionReducer | DocumentActionComponent[]) ``` #### DocumentActionDescription API 的接口和属性如下所示: 🌐 The interface and properties of the API look like the following: ```jsx interface DocumentActionDescription { label: string; onClick?: (event: React.SyntheticEvent) => Promise | boolean | void; icon?: React.ReactNode; /** * @default false */ disabled?: boolean; /** * @default 'panel' * @description Where the action should be rendered. */ position?: DocumentActionPosition | DocumentActionPosition[]; dialog?: DialogOptions | NotificationOptions | ModalOptions; /** * @default 'secondary' */ variant?: ButtonProps['variant']; loading?: ButtonProps['loading']; } type DocumentActionPosition = 'panel' | 'header' | 'table-row' | 'preview' | 'relation-modal'; interface DialogOptions { type: 'dialog'; title: string; content?: React.ReactNode; variant?: ButtonProps['variant']; onConfirm?: () => void | Promise; onCancel?: () => void | Promise; } interface NotificationOptions { type: 'notification'; title: string; link?: { label: string; url: string; target?: string; }; content?: string; onClose?: () => void; status?: NotificationConfig['type']; timeout?: number; } interface ModalOptions { type: 'modal'; title: string; content: React.ComponentType<{ onClose: () => void; }> | React.ReactNode; footer?: React.ComponentType<{ onClose: () => void; }> | React.ReactNode; onClose?: () => void; } ``` ### `addDocumentHeaderAction` 使用此 API 向内容管理器的编辑视图的标题添加更多操作: 🌐 Use this API to add more actions to the header of the Edit view of the Content Manager: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-document-header-action.png) ```jsx addDocumentHeaderAction(actions: DescriptionReducer | HeaderActionComponent[]) ``` #### HeaderActionDescription API 的接口和属性如下所示: 🌐 The interface and properties of the API look like the following: ```jsx interface HeaderActionDescription { disabled?: boolean; label: string; icon?: React.ReactNode; type?: 'icon' | 'default'; onClick?: (event: React.SyntheticEvent) => Promise | boolean | void; dialog?: DialogOptions; options?: Array<{ disabled?: boolean; label: string; startIcon?: React.ReactNode; textValue?: string; value: string; }>; onSelect?: (value: string) => void; value?: string; } interface DialogOptions { type: 'dialog'; title: string; content?: React.ReactNode; footer?: React.ReactNode; } ``` ### `addBulkAction` 使用此 API 添加按钮,当在内容管理器的列表视图中选择条目时显示,就像“添加到发布”按钮一样: 🌐 Use this API to add buttons that show up when entries are selected on the List View of the Content Manager, just like the "Add to Release" button for instance: ![addEditViewSidePanel](/img/assets/content-manager-apis/add-bulk-action.png) ```jsx addBulkAction(actions: DescriptionReducer | BulkActionComponent[]) ``` #### BulkActionDescription API 的接口和属性如下所示: 🌐 The interface and properties of the API look like the following: ```jsx interface BulkActionDescription { dialog?: DialogOptions | NotificationOptions | ModalOptions; disabled?: boolean; icon?: React.ReactNode; label: string; onClick?: (event: React.SyntheticEvent) => void; /** * @default 'default' */ type?: 'icon' | 'default'; /** * @default 'secondary' */ variant?: ButtonProps['variant']; } ``` # 插件创建与设置 Source: https://docs.strapi.io/cms/plugins-development/create-a-plugin # 插件创建 {#plugin-creation} 🌐 Plugin creation 创建 Strapi 5 插件的方法有很多,但最快和推荐的方法是使用插件 SDK。 🌐 There are many ways to create a Strapi 5 plugin, but the fastest and recommended way is to use the Plugin SDK. 插件 SDK 是一组命令,用于开发插件以将其用作本地插件或将它们发布在 NPM 上和/或将它们提交到 Marketplace。 🌐 The Plugin SDK is a set of commands orientated around developing plugins to use them as local plugins or to publish them on NPM and/or submit them to the Marketplace. 使用插件 SDK,你无需在创建插件之前设置 Strapi 项目。 🌐 With the Plugin SDK, you do not need to set up a Strapi project before creating a plugin. 本指南涵盖了从零创建插件、将其链接到现有 Strapi 项目以及发布插件。如果你已经有现有插件,则可以改为对插件设置进行改造以使用插件 SDK 命令(请参阅 [插件 SDK 参考](/cms/plugins-development/plugin-sdk) 获取可用命令的完整列表)。 🌐 The present guide covers creating a plugin from scratch, linking it to an existing Strapi project, and publishing the plugin. If you already have an existing plugin, you can instead retrofit the plugin setup to utilise the Plugin SDK commands (please refer to the [Plugin SDK reference](/cms/plugins-development/plugin-sdk) for a full list of available commands). :::note 本指南假设你希望开发一个独立于你的 Strapi 项目的插件。然而,如果你想在现有项目中开发插件,步骤基本保持不变。如果你没有[使用 monorepo](#monorepo),步骤完全相同。 🌐 This guide assumes you want to develop a plugin external to your Strapi project. However, the steps largely remain the same if you want to develop a plugin within your existing project. If you are not [using a monorepo](#monorepo) the steps are exactly the same. ::: :::prerequisites 路径 `my-strapi-plugin` 可以替换为你想为插件命名的任何名称,包括它应该创建的位置的路径(例如,`code/strapi-plugins/my-new-strapi-plugin`)。 🌐 The path `my-strapi-plugin` can be replaced with whatever you want to call your plugin, including the path to where it should be created (e.g., `code/strapi-plugins/my-new-strapi-plugin`). 你将会通过一系列提示来帮助你设置插件。如果你对所有选项都选择了“是”,最终的结构将类似于默认的 [插件结构](/cms/plugins-development/plugin-structure)。 🌐 You will be ran through a series of prompts to help you setup your plugin. If you selected yes to all options the final structure will be similar to the default [plugin structure](/cms/plugins-development/plugin-structure). ### 将插件链接到你的项目 {#linking-the-plugin-to-your-project} 🌐 Linking the plugin to your project 为了在开发过程中测试你的插件,建议的方法是将其链接到 Strapi 项目。 🌐 In order to test your plugin during its development, the recommended approach is to link it to a Strapi project. 将你的插件链接到项目是通过 `watch:link` 命令完成的。该命令将输出关于如何将你的插件链接到 Strapi 项目的说明。 🌐 Linking your plugin to a project is done with the `watch:link` command. The command will output explanations on how to link your plugin to a Strapi project. 在新的终端窗口中,运行以下命令: 🌐 In a new terminal window, run the following commands: :::note 在上面的示例中,当将插件链接到项目时,我们使用插件的名称(`my-strapi-plugin`)。这是包的名称,而不是文件夹的名称。 🌐 In the above examples we use the name of the plugin (`my-strapi-plugin`) when linking it to the project. This is the name of the package, not the name of the folder. ::: 由于这个插件是通过 `node_modules` 安装的,你不需要显式地将它添加到你的 `plugins` [配置文件](/cms/configurations/plugins) 中,因此运行 [`develop command`](/cms/cli#strapi-develop) 来启动你的 Strapi 项目时会自动识别你的插件。 🌐 Because this plugin is installed via `node_modules` you won't need to explicity add it to your `plugins` [configuration file](/cms/configurations/plugins), so running the [`develop command`](/cms/cli#strapi-develop) to start your Strapi project will automatically pick up your plugin. 现在你的插件已链接到项目,运行 `yarn develop` 或 `npm run develop` 来启动 Strapi 应用。 🌐 Now that your plugin is linked to a project, run `yarn develop` or `npm run develop` to start the Strapi application. 你现在可以按照自己的方式开发插件了!如果你进行了服务器更改,你需要重启服务器以使更改生效。 🌐 You are now ready to develop your plugin how you see fit! If you are making server changes, you will need to restart your server for them to take effect. ### 构建用于发布的插件 {#building-the-plugin-for-publishing} 🌐 Building the plugin for publishing 当你准备发布你的插件时,你需要先构建它。为此,请运行以下命令: 🌐 When you are ready to publish your plugin, you will need to build it. To do this, run the following command: 上述命令不仅会构建插件,还会验证输出是否有效并准备好发布。然后,你可以像发布其他任何包一样,将你的插件发布到 NPM。 🌐 The above commands will not only build the plugin, but also verify that the output is valid and ready to be published. You can then publish your plugin to NPM as you would any other package. :::tip Upgrading from SDK Plugin v5 如果你正在从 `@strapi/sdk-plugin` v5 升级到 v6: 🌐 If you're upgrading from `@strapi/sdk-plugin` v5 to v6: * 从你的插件中删除任何 `packup.config.ts` 文件(它不再使用)。 * 依赖 `package.json#exports` 进行构建配置(它现在是自动派生的)。 * 如果你需要源映射,请在构建命令中添加 `--sourcemap`(它们现在默认是关闭的)。 不需要其他更改。 🌐 No other changes are required. ::: ## 在单体仓库环境中使用插件 SDK {#monorepo} 🌐 Working with the Plugin SDK in a monorepo environment 如果你在单一代码库环境中开发插件,则不需要使用 `watch:link` 命令,因为单一代码库工作区设置会处理符号链接。你可以改用 `watch` 命令。 🌐 If you are working with a monorepo environment to develop your plugin, you don't need to use the `watch:link` command because the monorepo workspace setup will handle the symlink. You can use the `watch` command instead. 然而,如果你正在编写管理代码,你可能会添加一个针对你的插件源代码的 `alias`,以便在管理面板的环境中更容易使用: 🌐 However, if you are writing admin code, you might add an `alias` that targets the source code of your plugin to make it easier to work with within the context of the admin panel: ```ts config.resolve.alias = { ...config.resolve.alias, 'my-strapi-plugin': path.resolve( __dirname, // We've assumed the plugin is local. '../plugins/my-strapi-plugin/admin/src' ), }; return config; }; ``` :::caution 因为服务器查看 `server/src/index.ts|js` 文件以导入你的插件代码,所以你必须使用 `watch` 命令,否则代码不会被转译,服务器将无法找到你的插件。 🌐 Because the server looks at the `server/src/index.ts|js` file to import your plugin code, you must use the `watch` command otherwise the code will not be transpiled and the server will not be able to find your plugin. ::: ### 使用本地插件的配置 {#configuration-with-a-local-plugin} 🌐 Configuration with a local plugin 由于插件 SDK 主要用于开发插件,而不是本地开发,因此需要手动调整本地插件的配置。 🌐 Since the Plugin SDK is primarily designed for developing plugins, not locally, the configuration needs to be adjusted manually for local plugins. 在本地开发你的插件时(使用 `@strapi/sdk-plugin`),你的插件配置文件如下例所示: 🌐 When developing your plugin locally (using `@strapi/sdk-plugin`), your plugins configuration file looks like in the following example: ```js title="/config/plugins.js|ts" myplugin: { enabled: true, resolve: `./src/plugins/local-plugin`, }, ``` 但是,此设置有时会导致以下错误: 🌐 However, this setup can sometimes lead to errors such as the following: ```js Error: 'X must be used within StrapiApp'; ``` 此错误通常发生在你的插件尝试导入核心 Strapi 功能时,例如使用: 🌐 This error often occurs when your plugin attempts to import core Strapi functionality, for example using: ```js ``` 要解决此问题,请从你的插件中将 `@strapi/strapi` 移除为开发依赖。这可以确保你的插件使用与主应用相同的 Strapi 核心模块实例,从而防止冲突及相关错误。 🌐 To resolve the issue, remove `@strapi/strapi` as a dev dependency from your plugin. This ensures that your plugin uses the same instance of Strapi's core modules as the main application, preventing conflicts and the associated errors. ## 在没有插件 SDK 的情况下,在多仓库环境中设置本地插件 {#setting-a-local-plugin-in-a-monorepo-environment-without-the-plugin-sdk} 🌐 Setting a local plugin in a monorepo environment without the Plugin SDK 在 monorepo 中,你可以通过在插件根目录添加 2 个入口点文件来配置本地插件,而无需使用插件 SDK: 🌐 In a monorepo, you can configure your local plugin without using the Plugin SDK by adding 2 entry point files at the root of your plugin: - 服务器入口点:`strapi-server.js|ts` - 管理员入口:`strapi-admin.js|ts` ### 服务器入口点 {#server-entry-point} 🌐 Server entry point 服务器入口文件初始化插件的服务器端功能。`strapi-server.js`(或其 TypeScript 版本)的预期结构是: 🌐 The server entry point file initializes your plugin's server-side functionalities. The expected structure for `strapi-server.js` (or its TypeScript variant) is: ```js module.exports = () => { return { register, config, controllers, contentTypes, routes, }; }; ``` 在这里,你导出一个函数,该函数返回插件的核心组件,如控制器、路由和配置。有关更多详细信息,请参考[服务器 API 参考](/cms/plugins-development/server-api)。 🌐 Here, you export a function that returns your plugin's core components such as controllers, routes, and configuration. For more details, please refer to the [Server API reference](/cms/plugins-development/server-api). ### 管理员入口 {#admin-entry-point} 🌐 Admin entry point 管理员入口文件在 Strapi 管理面板中设置你的插件。`strapi-admin.js`(或其 TypeScript 变体)的预期结构是: 🌐 The admin entry point file sets up your plugin within the Strapi admin panel. The expected structure for `strapi-admin.js` (or its TypeScript variant) is: ```js register(app) {}, bootstrap() {}, registerTrads({ locales }) {}, }; ``` 此对象包括用于向管理应用注册插件、执行引导操作以及处理翻译的方法。更多详情,请参阅 [管理员面板 API 参考](/cms/plugins-development/admin-panel-api)。 🌐 This object includes methods to register your plugin with the admin application, perform bootstrapping actions, and handle translations. For more details, please refer to the [Admin Panel API reference](/cms/plugins-development/admin-panel-api). :::tip 有关如何在 monorepo 环境中构建本地插件的完整示例,请查看我们的 。 ::: # 开发插件 Source: https://docs.strapi.io/cms/plugins-development/developing-plugins # 开发 Strapi 插件 {#developing-strapi-plugins} 🌐 Developing Strapi plugins Strapi 允许开发的插件其工作方式与内置插件或可从 :::strapi Custom fields plugins 插件也可以用于向 Strapi 添加 [自定义字段](/cms/features/custom-fields)。 🌐 Plugins can also be used to add [custom fields](/cms/features/custom-fields) to Strapi. ::: ## 指南 {#guides} 🌐 Guides
:::strapi Additional resources The 还可以包括在开发 Strapi 插件时有用的额外信息。 ::: # 如何从插件创建管理员权限 Source: https://docs.strapi.io/cms/plugins-development/guides/admin-permissions-for-plugins # 如何从插件创建管理员权限 {#how-to-create-admin-permissions-from-plugins} 🌐 How to create admin permissions from plugins 在[开发 Strapi 插件](/cms/plugins-development/developing-plugins)时,你可能希望为你的插件创建管理员权限。通过这样做,你可以接入 Strapi 的[RBAC 系统](/cms/features/rbac),有选择地为插件的某些部分授予权限。 🌐 When [developing a Strapi plugin](/cms/plugins-development/developing-plugins), you might want to create admin permissions for your plugin. By doing that you can hook in to the [RBAC system](/cms/features/rbac) of Strapi to selectively grant permissions to certain pieces of your plugin. 要为你的 Strapi 插件创建管理员权限,你需要在服务器端注册这些权限,然后再在管理端实现它们。 🌐 To create admin permissions for your Strapi plugin, you'll need to register them on the server side before implementing them on the admin side. ## 在服务器端注册权限 {#register-the-permissions-server-side} 🌐 Register the permissions server side 每个单独的权限都必须在插件的引导函数中注册,如下所示: 🌐 Each individual permission has to registered in the bootstrap function of your plugin, as follows: ## 在管理面板端实现权限 {#implement-permissions-on-the-admin-panel-side} 🌐 Implement permissions on the admin panel side 在我们能够在管理员面板端实现权限之前,我们必须在一个可重用的配置文件中定义它们。这个文件可以存储在插件管理员代码的任何位置。你可以按如下方式操作: 🌐 Before we can implement our permissions on the admin panel side we have to define them in a reusable configuration file. This file can be stored anywhere in your plugin admin code. You can do that as follows: ```js title="/src/plugins/my-plugin/admin/src/permissions.js|ts" const pluginPermissions = { 'accessOverview': [{ action: 'plugin::my-plugin.overview.access', subject: null }], 'accessSidebar': [{ action: 'plugin::my-plugin.sidebar.access', subject: null }], }; ``` ### 页面权限 {#page-permissions} 🌐 Page permissions 一旦你创建了配置文件,你就可以准备实现你的权限。如果你使用 [plugin SDK init 命令](/cms/plugins-development/plugin-sdk#npx-strapisdk-plugin-init) 启动了你的插件,你将会有一个示例 `HomePage.tsx` 文件。要实现页面权限,你可以执行以下操作: 🌐 Once you've created the configuration file you are ready to implement your permissions. If you've bootstrapped your plugin using the [plugin SDK init command](/cms/plugins-development/plugin-sdk#npx-strapisdk-plugin-init), you will have an example `HomePage.tsx` file. To implement page permissions you can do the following: ```js title="/src/plugins/my-plugin/admin/src/pages/HomePage.jsx|tsx" {2,5,12,16} const HomePage = () => { const { formatMessage } = useIntl(); return ( ); }; ``` 你可以看到我们如何将权限配置文件与 `` 组件一起使用,以要求特定权限才能查看此页面。 🌐 You can see how we use our permissions configuration file together with the `` component to require specific permissions in order to view this page. ### 菜单链接权限 {#menu-link-permissions} 🌐 Menu link permissions 前面的例子确保了直接访问你页面的用户的权限会被验证。然而,你可能也想删除指向该页面的菜单链接。为此,你需要对 `addMenuLink` 实现进行修改。你可以按如下方式操作: 🌐 The previous example makes sure that the permissions of a user that visits your page directly will be validated. However, you might want to remove the menu link to that page as well. To do that, you'll have to make a change to the `addMenuLink` implementation. You can do as follows: ```js title="/src/plugins/my-plugin/admin/src/index.js|ts" {21-23,5} register(app) { app.addMenuLink({ to: `plugins/${PLUGIN_ID}`, icon: PluginIcon, intlLabel: { id: `${PLUGIN_ID}.plugin.name`, defaultMessage: PLUGIN_ID, }, Component: async () => { const { App } = await import('./pages/App'); return App; }, permissions: [ pluginPermissions.accessOverview[0], ], }); app.registerPlugin({ id: PLUGIN_ID, initializer: Initializer, isReady: false, name: PLUGIN_ID, }); }, }; ``` ### 使用 `useRBAC` 钩子的自定义权限 {#custom-permissions-with-the-userbac-hook} 🌐 Custom permissions with the `useRBAC` hook 为了对管理员用户的权限获得更多控制,你可以使用 `useRBAC` 钩子。通过这个钩子,你可以像下面的示例一样按自己的意愿使用权限验证: 🌐 To get even more control over the permission of the admin user you can use the `useRBAC` hook. With this hook you can use the permissions validation just like you want, as in the following example: ```js title="/src/plugins/my-plugin/admin/src/components/Sidebar.jsx|tsx" const Sidebar = () => { const { allowedActions: { canAccessSidebar }, } = useRBAC(pluginPermissions); if (!canAccessSidebar) { return null; } return (
Sidebar component
); }; ``` # 如何为 Strapi 插件创建组件 Source: https://docs.strapi.io/cms/plugins-development/guides/create-components-for-plugins # 如何为 Strapi 插件创建组件 {#how-to-create-components-for-strapi-plugins} 🌐 How to create components for Strapi plugins 在[开发 Strapi 插件](/cms/plugins-development/developing-plugins)时,你可能希望为你的插件创建可重用的组件。Strapi 中的组件是可重用的数据结构,可以在不同的内容类型中使用。 🌐 When [developing a Strapi plugin](/cms/plugins-development/developing-plugins), you might want to create reusable components for your plugin. Components in Strapi are reusable data structures that can be used across different content-types. 要为 Strapi 插件创建组件,你需要遵循与创建内容类型类似的方法,但有一些具体的区别。 🌐 To create components for your Strapi plugin, you'll need to follow a similar approach to creating content-types, but with some specific differences. ## 创建组件 {#creating-components} 🌐 Creating components 你可以通过两种不同的方式为你的插件创建组件:使用内容类型构建器(推荐方式)或手动创建。 🌐 You can create components for your plugins in 2 different ways: using the Content-Type Builder (recommended way) or manually. ### 使用内容类型构建器 {#using-the-content-type-builder} 🌐 Using the Content-Type Builder 建议通过管理面板中的 Content-Type Builder 为插件创建组件。 🌐 The recommended way to create components for your plugin is through the Content-Type Builder in the admin panel. [Content-Type Builder 文档](/cms/features/content-type-builder#new-component) 提供了关于此过程的更多详细信息。 🌐 The [Content-Type Builder documentation](/cms/features/content-type-builder#new-component) provides more details on this process. ### 手动创建组件 {#creating-components-manually} 🌐 Creating components manually 如果你更喜欢手动创建组件,则需要: 🌐 If you prefer to create components manually, you'll need to: 1. 在插件结构中创建组件模式。 2. 确保组件已正确注册。 插件的组件应放置在插件结构中的适当目录中。通常,你会在插件的服务器部分创建它们(参见[插件结构文档](/cms/plugins-development/plugin-structure))。 🌐 Components for plugins should be placed in the appropriate directory within your plugin structure. You would typically create them within the server part of your plugin (see [plugin structure documentation](/cms/plugins-development/plugin-structure)). 有关 Strapi 中组件的更详细信息,你可以参考 [模型属性文档](/cms/backend-customization/models#components-json)。 🌐 For more detailed information about components in Strapi, you can refer to the [Model attributes documentation](/cms/backend-customization/models#components-json). ## 审查组件结构 {#reviewing-the-component-structure} 🌐 Reviewing the component structure Strapi 中的组件在定义中遵循以下格式: 🌐 Components in Strapi follow the following format in their definition: ```javascript title="/my-plugin/server/components/category/component-name.json" { "attributes": { "myComponent": { "type": "component", "repeatable": true, "component": "category.componentName" } } } ``` ## 组件模式示例 {#component-schema-example} 🌐 Component schema example 组件模式定义了可重用数据片段的结构。以下是一个插件组件模式的示例: 🌐 A component schema defines the structure of a reusable data fragment. Here is an example of a component schema for a plugin: ```json title="my-plugin/server/components/my-category/my-component.json" { "collectionName": "components_my_category_my_components", "info": { "displayName": "My Component", "icon": "align-justify" }, "attributes": { "name": { "type": "string", "required": true }, "description": { "type": "text" } } } ``` 此配置确保当在启用 `pluginOptions` 可见性的内容类型中使用时,你的组件将在内容类型构建器和内容管理器中都可用。 🌐 This configuration ensures your components will be available in both the Content-Type Builder and Content Manager when used in a content-type that has `pluginOptions` visibility enabled. # 如何通过 Strapi 插件将数据从服务器传递到管理面板 Source: https://docs.strapi.io/cms/plugins-development/guides/pass-data-from-server-to-admin # 如何通过 Strapi 插件将数据从服务器传递到管理面板 {#how-to-pass-data-from-server-to-admin-panel-with-a-strapi-plugin} 🌐 How to pass data from server to admin panel with a Strapi plugin Strapi 是 **无头** 。管理面板与服务器完全分开。 在[开发 Strapi 插件](/cms/plugins-development/developing-plugins)时,你可能想将数据从 `/server` 文件夹传递到 `/admin` 文件夹。在 `/server` 文件夹中,你可以访问 Strapi 对象并进行数据库查询,而在 `/admin` 文件夹中则不能。 🌐 When [developing a Strapi plugin](/cms/plugins-development/developing-plugins) you might want to pass data from the `/server` to the `/admin` folder. Within the `/server` folder you have access to the Strapi object and can do database queries whereas in the `/admin` folder you can't. 可以使用管理面板的 Axios 实例将数据从 `/server` 文件夹传递到 `/admin` 文件夹: 🌐 Passing data from the `/server` to the `/admin` folder can be done using the admin panel's Axios instance: 要将数据从 `/server` 文件夹传递到 `/admin` 文件夹,你首先需要 [创建自定义管理路由](#create-a-custom-admin-route),然后 [在管理面板中获取返回的数据](#get-the-data-in-the-admin-panel)。 🌐 To pass data from the `/server` to `/admin` folder you would first [create a custom admin route](#create-a-custom-admin-route) and then [get the data returned in the admin panel](#get-the-data-in-the-admin-panel). ## 创建自定义管理员路由 {#create-a-custom-admin-route} 🌐 Create a custom admin route 管理路由就像你为任何控制器设置的路由,只是 `type: 'admin'` 声明会将它们从通用 API 路由中隐藏,并允许你从管理面板访问它们。 🌐 Admin routes are like the routes that you would have for any controller, except that the `type: 'admin'` declaration hides them from the general API router, and allows you to access them from the admin panel. 以下代码将为 `my-plugin` 插件声明一个自定义管理路由: 🌐 The following code will declare a custom admin route for the `my-plugin` plugin: ```js title="/my-plugin/server/routes/index.js" module.exports = { 'pass-data': { type: 'admin', routes: [ { method: 'GET', path: '/pass-data', handler: 'myPluginContentType.index', config: { policies: [], auth: false, }, }, ] } // ... }; ``` 当你向 `/my-plugin/pass-data` URL 端点发送 GET 请求时,此路由将调用 `myPluginContentType` 控制器的 `index` 方法。 🌐 This route will call the `index` method of the `myPluginContentType` controller when you send a GET request to the `/my-plugin/pass-data` URL endpoint. 让我们创建一个基本的自定义控制器,它只返回一个简单的文本: 🌐 Let's create a basic custom controller that simply returns a simple text: ```js title="/my-plugin/server/controllers/my-plugin-content-type.js" 'use strict'; module.exports = { async index(ctx) { ctx.body = 'You are in the my-plugin-content-type controller!'; } } ``` 这意味着当向 `/my-plugin/pass-data` URL 端点发送 GET 请求时,你应该在响应中收到返回的 `You are in the my-plugin-content-type controller!` 文本。 🌐 This means that when sending a GET request to the `/my-plugin/pass-data` URL endpoint, you should get the `You are in the my-plugin-content-type controller!` text returned with the response. ## 在管理面板中获取数据 {#get-the-data-in-the-admin-panel} 🌐 Get the data in the admin panel 从管理员面板组件发送到我们为其定义了自定义路由 `/my-plugin/pass-data` 的端点的任何请求现在都应该返回由自定义控制器返回的文本消息。 🌐 Any request sent from an admin panel component to the endpoint for which we defined the custom route `/my-plugin/pass-data` should now return the text message returned by the custom controller. 例如,如果你创建一个 `/admin/src/api/foobar.js` 文件并复制粘贴以下代码示例: 🌐 So for instance, if you create an `/admin/src/api/foobar.js` file and copy and paste the following code example: ```js title="/my-plugin/admin/src/api/foobar.js" const foobarRequests = { getFoobar: async () => { const data = await axios.get(`/my-plugin/pass-data`); return data; }, }; ``` 你将能够在管理面板组件的代码中使用 `foobarRequests.getFoobar()`,并让它返回包含数据的 `You are in the my-plugin-content-type controller!` 文本。 🌐 You will be able to use `foobarRequests.getFoobar()` in the code of an admin panel component and have it return the `You are in the my-plugin-content-type controller!` text with the data. 例如,在一个 React 组件中,你可以使用 `useEffect` 在组件初始化后获取数据: 🌐 For instance, within a React component, you could use `useEffect` to get the data after the component initializes: ```js title="/my-plugin/admin/src/components/MyComponent/index.js" const [foobar, setFoobar] = useState([]); // … useEffect(() => { foobarRequests.getFoobar().then(res => { setFoobar(res.data); }); }, [setFoobar]); // … ``` 这将设置组件状态中 `foobar` 数据内的 `You are in the my-plugin-content-type controller!` 文本。 🌐 This would set the `You are in the my-plugin-content-type controller!` text within the `foobar` data of the component's state. # 如何从 Strapi 插件存储和访问数据 Source: https://docs.strapi.io/cms/plugins-development/guides/store-and-access-data # 如何从 Strapi 插件存储和访问数据 {#how-to-store-and-access-data-from-a-strapi-plugin} 🌐 How to store and access data from a Strapi plugin 要使用 Strapi [插件](/cms/plugins-development/developing-plugins) 存储数据,请使用插件内容类型。插件内容类型的工作方式与其他 [内容类型](/cms/backend-customization/models) 完全相同。一旦 [创建](#create-a-content-type-for-your-plugin) 内容类型,你就可以开始 [与数据交互](#interact-with-data-from-the-plugin) 了。 🌐 To store data with a Strapi [plugin](/cms/plugins-development/developing-plugins), use a plugin content-type. Plugin content-types work exactly like other [content-types](/cms/backend-customization/models). Once the content-type is [created](#create-a-content-type-for-your-plugin), you can start [interacting with the data](#interact-with-data-from-the-plugin). ## 为你的插件创建一个内容类型 {#create-a-content-type-for-your-plugin} 🌐 Create a content-type for your plugin 要使用 CLI 生成器创建内容类型,请在插件的 `server/src/` 目录中的终端运行以下命令: 🌐 To create a content-type with the CLI generator, run the following command in a terminal within the `server/src/` directory of your plugin: 生成器 CLI 是交互式的,会询问一些关于内容类型及其包含的属性的问题。先回答第一个问题,然后在 `Where do you want to add this model?` 问题中,选择 `Add model to existing plugin` 选项,并在提示时输入相关插件的名称。 🌐 The generator CLI is interactive and asks a few questions about the content-type and the attributes it will contain. Answer the first questions, then for the `Where do you want to add this model?` question, choose the `Add model to existing plugin` option and type the name of the related plugin when asked.
Generating a content-type plugin with the CLI
strapi generate content-type CLI 生成器用于为插件创建一个基础内容类型。

CLI 将生成一些使用你的插件所需的代码,其中包括以下内容: 🌐 The CLI will generate some code required to use your plugin, which includes the following: - 内容类型模式([content-type schema](/cms/backend-customization/models#model-schema)) - 以及一个基本的 [controller](/cms/backend-customization/controllers)、[service](/cms/backend-customization/services) 和 [route](/cms/backend-customization/routes) 用于内容类型 :::tip 你可能希望完全通过 CLI 生成器创建你的内容类型的整个结构,或者直接创建和编辑 `schema.json` 文件。我们建议你先使用 CLI 生成器创建一个简单的内容类型,然后利用管理面板中的 [内容类型构建器](/cms/features/content-type-builder) 编辑你的内容类型。 🌐 You may want to create the whole structure of your content-types either entirely with the CLI generator or by directly creating and editing `schema.json` files. We recommend you first create a simple content-type with the CLI generator and then leverage the [Content-Type Builder](/cms/features/content-type-builder) in the admin panel to edit your content-type. 如果你的内容类型在管理面板中不可见,你可能需要在内容类型模式的 `pluginOptions` 对象中将 `content-manager.visible` 和 `content-type-builder.visible` 参数设置为 `true`: 🌐 If your content-type is not visible in the admin panel, you might need to set the `content-manager.visible` and `content-type-builder.visible` parameters to `true` in the `pluginOptions` object of the content-type schema:
在管理面板中使插件内容类型可见: 示例 `schema.json` 文件中以下高亮显示的行展示了如何使插件内容类型在内容类型构建器和内容管理器中可见: 🌐 The following highlighted lines in an example `schema.json` file show how to make a plugin content-type visible to the Content-Type Builder and Content-Manager: ```json title="/server/content-types/my-plugin-content-type/schema.json" {13-20} showLineNumbers { "kind": "collectionType", "collectionName": "my_plugin_content_types", "info": { "singularName": "my-plugin-content-type", "pluralName": "my-plugin-content-types", "displayName": "My Plugin Content-Type" }, "options": { "draftAndPublish": false, "comment": "" }, "pluginOptions": { "content-manager": { "visible": true }, "content-type-builder": { "visible": true } }, "attributes": { "name": { "type": "string" } } } ```
::: ### 确保导入插件内容类型 {#ensure-plugin-content-types-are-imported} 🌐 Ensure plugin content-types are imported CLI 生成器可能没有导入你插件的所有相关内容类型文件,因此在 `strapi generate content-type` CLI 命令运行完成后,你可能需要进行以下调整: 🌐 The CLI generator might not have imported all the related content-type files for your plugin, so you might have to make the following adjustments after the `strapi generate content-type` CLI command has finished running: 1. 在 `/server/index.js` 文件中,导入内容类型: ```js {7,22} showLineNumbers title="/server/index.js" 'use strict'; const register = require('./register'); const bootstrap = require('./bootstrap'); const destroy = require('./destroy'); const config = require('./config'); const contentTypes = require('./content-types'); const controllers = require('./controllers'); const routes = require('./routes'); const middlewares = require('./middlewares'); const policies = require('./policies'); const services = require('./services'); module.exports = { register, bootstrap, destroy, config, controllers, routes, services, contentTypes, policies, middlewares, }; ``` 2. 在 `/server/content-types/index.js` 文件中,导入 content-type 文件夹: ```js title="/server/content-types/index.js" 'use strict'; module.exports = { // In the line below, replace my-plugin-content-type // with the actual name and folder path of your content type "my-plugin-content-type": require('./my-plugin-content-type'), }; ``` 3. 确保 `/server/content-types/[your-content-type-name]` 文件夹不仅包含由 CLI 生成的 `schema.json` 文件,还包含一个 `index.js` 文件,该文件使用以下代码导出内容类型: ```js title="/server/content-types/my-plugin-content-type/index.js 'use strict'; const schema = require('./schema'); module.exports = { schema, }; ``` ## 与插件中的数据进行交互 {#interact-with-data-from-the-plugin} 🌐 Interact with data from the plugin 为插件创建内容类型后,你可以创建、读取、更新和删除数据。 🌐 Once you have created a content-type for your plugin, you can create, read, update, and delete data. :::note 插件只能与 `/server` 文件夹中的数据交互。如果你需要从管理面板更新数据,请参考 [传递数据指南](/cms/plugins-development/guides/pass-data-from-server-to-admin)。 🌐 A plugin can only interact with data from the `/server` folder. If you need to update data from the admin panel, please refer to the [passing data guide](/cms/plugins-development/guides/pass-data-from-server-to-admin). ::: 要创建、读取、更新和删除数据,你可以使用 [Document Service API](/cms/api/document-service) 或 [Query Engine API](/cms/api/query-engine)。虽然建议使用 Document Service API,特别是当你需要访问组件或动态区域时,但如果你需要不受限制地访问底层数据库,Query Engine API 也非常有用。 🌐 To create, read, update, and delete data, you can use either the [Document Service API](/cms/api/document-service) or the [Query Engine API](/cms/api/query-engine). While it's recommended to use the Document Service API, especially if you need access to components or dynamic zones, the Query Engine API is useful if you need unrestricted access to the underlying database. 在文档服务和查询引擎 API 查询中使用 `plugin::your-plugin-slug.the-plugin-content-type-name` 语法来标识内容类型。 🌐 Use the `plugin::your-plugin-slug.the-plugin-content-type-name` syntax for content-type identifiers in Document Service and Query Engine API queries. **示例:** 以下是如何查找为名为 `my-plugin` 的插件创建的 `my-plugin-content-type` 集合类型的所有条目: 🌐 Here is how to find all the entries for the `my-plugin-content-type` collection type created for a plugin called `my-plugin`: ```js // Using the Document Service API let data = await strapi.documents('plugin::my-plugin.my-plugin-content-type').findMany(); // Using the Query Engine API let data = await strapi.db.query('plugin::my-plugin.my-plugin-content-type').findMany(); ```` :::tip 你可以通过 `strapi` 对象访问数据库,该对象可以在 `middlewares`、`policies`、`controllers`、`services` 中找到,也可以从 `register`、`boostrap`、`destroy` 生命周期函数中获取。 🌐 You can access the database via the `strapi` object which can be found in `middlewares`, `policies`, `controllers`, `services`, as well as from the `register`, `boostrap`, `destroy` lifecycle functions. ::: # 插件 SDK 参考 Source: https://docs.strapi.io/cms/plugins-development/plugin-sdk # 插件 SDK 参考 {#plugin-sdk-reference} 🌐 Plugin SDK reference 插件 SDK 是由包提供的一组命令 ,围绕开发插件,以便将它们作为本地插件使用,或发布到 NPM 和/或提交到市场。 🌐 The Plugin SDK is set of commands provided by the package orientated around developing plugins to use them as local plugins or to publish them on NPM and/or submit them to the Marketplace. 本文件列出了可用的插件 SDK 命令。[相关指南](/cms/plugins-development/create-a-plugin)说明了如何使用这些命令从头创建插件,将其链接到现有项目,并发布它。 🌐 The present documentation lists the available Plugin SDK commands. The [associated guide](/cms/plugins-development/create-a-plugin) illustrates how to use these commands to create a plugin from scratch, link it to an existing project, and publish it. ## npx @strapi/sdk-plugin init 在给定路径创建一个新插件。 🌐 Create a new plugin at a given path. ```bash npx @strapi/sdk-plugin init ``` | 参数 | 类型 | 描述 | 默认值 || --- | :----: | --- | --- || `path` | 字符串 | 插件的路径 | `./src/plugins/my-plugin` | | 选项 | 类型 | 描述 | 默认值 || --- | :--: | --- | --- || `-d, --debug` | - | 启用调试模式并输出详细日志 | false || `--silent` | - | 不记录任何日志 | false | ## strapi 插件 构建 {#strapi-plugin-build} 🌐 strapi-plugin build 打包 Strapi 插件以进行发布。 🌐 Bundle the Strapi plugin for publishing. ```bash strapi-plugin build ``` | 选项 | 类型 | 描述 | 默认值 || --- | :----: | --- | --- || `--force` | 字符串 | 自动对所有提示回答“是”,包括可能具有破坏性的请求,并以非交互方式运行。 | - || `-d, --debug` | - | 启用调试模式并显示详细日志 | false || `--silent` | - | 不记录任何日志 | false || `--minify` | - | 压缩输出 | false || `--sourcemap` | - | 生成源映射 | false | :::note 从 v6 开始,构建配置会自动从你的 `package.json` exports 字段中派生。不需要任何配置文件(例如 `vite.config.ts` 或 `rollup.config.ts`)。 🌐 As of v6, the build configuration is automatically derived from your `package.json` exports field. No configuration file (such as `vite.config.ts` or `rollup.config.ts`) is needed. ::: ## strapi 插件 watch:link {#strapi-plugin-watchlink} 🌐 strapi-plugin watch:link 在插件发生更改时自动重新编译插件并运行 `yalc push --publish`。 🌐 Recompiles the plugin automatically on changes and runs `yalc push --publish`. 为了测试目的,将你的插件链接到现有应用以在真实条件下进行实验是非常方便的。此命令旨在帮助你简化此过程。 🌐 For testing purposes, it is very convenient to link your plugin to an existing application to experiment with it in real condition. This command is made to help you streamline this process. ```bash strapi-plugin watch:link ``` | 选项 | 类型 | 描述 | 默认值 || --- | :--: | --- | --- || `-d, --debug` | - | 启用调试模式并输出详细日志 | false || `--silent` | - | 不记录任何日志 | false | ## strapi 插件 监视 {#strapi-plugin-watch} 🌐 strapi-plugin watch 监视插件源代码的任何更改并每次重建它。在实现插件并在应用中测试时非常有用。 🌐 Watch the plugin source code for any change and rebuild it everytime. Useful when implementing your plugin and testing it in an application. ```bash strapi-plugin watch ``` | 选项 | 类型 | 描述 | 默认值 || --- | :--: | --- | --- || `-d, --debug` | - | 启用调试模式并输出详细日志 | false || `--silent` | - | 不记录任何日志 | false | ## strapi 插件验证 {#strapi-plugin-verify} 🌐 strapi-plugin verify 在发布插件之前验证插件的输出。 🌐 Verify the output of the plugin before publishing it. ```bash strapi-plugin verify ``` | 选项 | 类型 | 描述 | 默认值 || --- | :--: | --- | --- || `-d, --debug` | - | 启用调试模式并输出详细日志 | false || `--silent` | - | 不记录任何日志 | false | # 插件结构 Source: https://docs.strapi.io/cms/plugins-development/plugin-structure # 插件结构 {#plugin-structure} 🌐 Plugin structure 当使用 [Plugin SDK 创建插件](/cms/plugins-development/create-a-plugin) 时,Strapi 会在 `/src/plugins/my-plugin` 文件夹中为你生成以下模板结构: 🌐 When [creating a plugin with Plugin SDK](/cms/plugins-development/create-a-plugin), Strapi generates the following boilerplate structure for you in the `/src/plugins/my-plugin` folder: Strapi 插件分为 2 部分,每个部分位于不同的文件夹中并提供不同的 API: 🌐 A Strapi plugin is divided into 2 parts, each living in a different folder and offering a different API: | 插件部分 | 描述 | 文件夹 | API ||-------------|-------------|--------------|-----|| 管理面板 | 包括将在[管理面板](/cms/intro)中可见的内容(组件、导航、设置等) | `admin/` |[管理面板 API](/cms/plugins-development/admin-panel-api)|| 后端服务器 | 包括与[后端服务器](/cms/backend-customization)相关的内容(内容类型、控制器、中间件等) |`server/` |[服务器 API](/cms/plugins-development/server-api)|
:::note Notes about the usefulness of the different parts for your specific use case - **仅服务器插件**:你可以创建一个仅使用服务器部分来增强应用 API 的插件。例如,该插件可以拥有其自身可见或不可见的内容类型、控制器操作和路由,这些对于特定用例非常有用。在这种情况下,你的插件不需要在管理面板中拥有界面。 - **管理员面板插件 vs. 特定应用的自定义**:你可以创建一个插件来将一些组件注入到管理员面板中。然而,你也可以通过创建一个 `/src/admin/index.js` 文件并调用 `bootstrap` 生命周期函数来注入你的组件来实现这一点。在这种情况下,是否创建插件取决于你是否打算重用和分发代码,或者它只是对一个独特的 Strapi 应用有用。 :::
:::strapi What to read next? Strapi 插件开发之旅的下一步将要求你使用任何 Strapi 插件 API。 🌐 The next steps of your Strapi plugin development journey will require you to use any of the Strapi plugins APIs. 2 种不同类型的资源可帮助你了解如何使用插件 API: - [管理面板 API](/cms/plugins-development/admin-panel-api) 和 [服务器 API](/cms/plugins-development/server-api) 的参考文档概述了使用 Strapi 插件可以实现的功能。 - [指南](/cms/plugins-development/developing-plugins#guides) 涵盖了一些特定的、基于使用场景的示例。 ::: # 插件扩展 Source: https://docs.strapi.io/cms/plugins-development/plugins-extension # 插件扩展 {#plugins-extension} 🌐 Plugins extension Strapi 带有可以从 [Marketplace](/cms/plugins/installing-plugins-via-marketplace#installing-marketplace-plugins-and-providers) 安装的插件,也可以作为 npm 包安装。你也可以创建自己的插件(参见 [插件开发](/cms/plugins-development/developing-plugins))或扩展现有插件。 🌐 Strapi comes with plugins that can be installed from the [Marketplace](/cms/plugins/installing-plugins-via-marketplace#installing-marketplace-plugins-and-providers) or as npm packages. You can also create your own plugins (see [plugins development](/cms/plugins-development/developing-plugins)) or extend the existing ones. :::warning * 任何插件更新都可能会破坏该插件的扩展。 * 当需要时,Strapi 的新版本将会发布迁移指南,但这些指南从不涵盖插件扩展。如果需要进行大量自定义,请考虑分叉插件。 * 目前,插件的管理面板部分只能使用 进行扩展,但请注意,这样做可能会在未来的 Strapi 版本中破坏你的插件。 ::: 插件扩展代码位于 `./src/extensions` 文件夹(参见 [项目结构](/cms/project-structure))。一些插件会自动在该处创建文件,准备进行修改。 🌐 Plugin extensions code is located in the `./src/extensions` folder (see [project structure](/cms/project-structure)). Some plugins automatically create files there, ready to be modified.
扩展文件夹结构示例 ```bash /extensions /some-plugin-to-extend strapi-server.js|ts /content-types /some-content-type-to-extend schema.json /another-content-type-to-extend schema.json /another-plugin-to-extend strapi-server.js|ts ```
插件可以通过两种方式扩展: 🌐 Plugins can be extended in 2 ways: - [扩展插件的内容类型](#extending-a-plugins-content-types) - [扩展插件的接口](#extending-a-plugins-interface)(例如添加控制器、服务、策略、中间件等) ## 扩展插件的内容类型 {#extending-a-plugins-content-types} 🌐 Extending a plugin's content-types 插件的内容类型可以通过两种方式扩展:使用 `strapi-server.js|ts` 中的编程接口,以及通过重写内容类型的架构。 🌐 A plugin's Content-Types can be extended in 2 ways: using the programmatic interface within `strapi-server.js|ts` and by overriding the content-types schemas. 内容类型的最终架构取决于以下加载顺序: 🌐 The final schema of the content-types depends on the following loading order: 1. 原始插件的内容类型, 2. `./src/extensions/plugin-name/content-types/content-type-name/schema.json` 中定义的 [schema](/cms/backend-customization/models#model-schema) 中声明所覆盖的内容类型 3. [`strapi-server.js|ts` 导出的 `contentTypes`](/cms/plugins-development/server-content-types) 中的内容类型声明 4. Strapi 应用中 [`register()` 函数](/cms/configurations/functions#register) 的内容类型声明 要覆盖插件的 [content-types](/cms/backend-customization/models): 🌐 To overwrite a plugin's [content-types](/cms/backend-customization/models): 1. _(可选)_ 如果 `./src/extensions` 文件夹尚不存在,请在应用根目录下创建该文件夹。 2. 创建一个与要扩展的插件同名的子文件夹。 3. 创建一个 `content-types` 子文件夹。 4. 在 `content-types` 子文件夹内,创建另一个与要覆盖的内容类型相同 [singularName](/cms/backend-customization/models#model-information) 的子文件夹。 5. 在这个 `content-types/name-of-content-type` 子文件夹中,在一个 `schema.json` 文件中定义该内容类型的新架构(参见 [schema](/cms/backend-customization/models#model-schema) 文档)。 6. _(可选)_ 对每种内容类型重复步骤 4 和 5 以进行覆盖。 ## 扩展插件的界面 {#extending-a-plugins-interface} 🌐 Extending a plugin's interface 当 Strapi 应用初始化时,插件、扩展和全局生命周期函数事件按以下顺序发生: 🌐 When a Strapi application is initializing, plugins, extensions and global lifecycle functions events happen in the following order: 1. 插件已加载并公开其接口。 2. `./src/extensions` 中的文件已加载。 3. `./src/index.js|ts` 中的 `register()` 和 `bootstrap()` 函数被调用。 插件的接口可以在步骤 2(即在 `./src/extensions` 内)或步骤 3(即在 `./src/index.js|ts` 内)进行扩展。 🌐 A plugin's interface can be extended at step 2 (i.e. within `./src/extensions`) or step 3 (i.e. inside `./src/index.js|ts`). :::note 如果你的 Strapi 项目是基于 TypeScript 的,请确保 `index` 文件具有 TypeScript 扩展名(即 `src/index.ts`),否则它将无法被编译。 🌐 If your Strapi project is TypeScript-based, please ensure that the `index` file has a TypeScript extension (i.e., `src/index.ts`) otherwise it will not be compiled. ::: ### 在扩展文件夹内 {#within-the-extensions-folder} 🌐 Within the extensions folder 要使用 `./src/extensions` 文件夹扩展插件的服务器接口: 🌐 To extend a plugin's server interface using the `./src/extensions` folder: 1. _(可选)_ 如果 `./src/extensions` 文件夹尚不存在,请在应用根目录下创建该文件夹。 2. 创建一个与要扩展的插件同名的子文件夹。 3. 创建一个 `strapi-server.js|ts` 文件,以使用 [Server API](/cms/plugins-development/server-api) 扩展插件的后端。 4. 在此文件中,定义并导出一个函数。该函数接收 `plugin` 接口作为参数,以便可以扩展它。
后端扩展示例 ```js title="./src/extensions/some-plugin-to-extend/strapi-server.js|ts" module.exports = (plugin) => { plugin.controllers.controllerA.find = (ctx) => {}; plugin.policies[newPolicy] = (ctx) => {}; plugin.routes['content-api'].routes.push({ method: 'GET', path: '/route-path', handler: 'controller.action', }); return plugin; }; ```
:::note `strapi-server.js|ts` 文件也是你可以通过替换上传插件的 `generateFileName()` 函数来覆盖图片功能的地方,从而生成自定义图片名称。 🌐 The `strapi-server.js|ts` file is also where you can override the image function, by replacing the Upload plugin's `generateFileName()` function so that it generates custom image names.
自定义文件命名逻辑示例 ```js title="./src/extensions/upload/strapi-server.js|ts" module.exports = (plugin) => { plugin.services['image-manipulation'].generateFileName = (file) => { // Example: prefix a timestamp before the generated base name return `${Date.now()}_${name}`; }; return plugin; }; ```
::: `generateFileName()` 属于上传插件的 `image-manipulation` 服务,并期望一个单一的 `name: string` 参数。 :::caution 此自定义依赖于内部上传插件服务(`image-manipulation`)。内部扩展点不是 Strapi 稳定的公共 API 的一部分,可能会在不同版本之间发生变化。 🌐 This customization relies on an internal Upload plugin service (`image-manipulation`). Internal extension points are not part of Strapi's stable public API and can change between versions. ::: ### 在注册和引导函数中 {#within-the-register-and-bootstrap-functions} 🌐 Within the register and bootstrap functions 要在 `./src/index.js|ts` 中扩展插件的接口,请使用整个项目的 `bootstrap()` 和 `register()` [函数](/cms/configurations/functions),并通过 [getter](/cms/plugins-development/server-getters-usage) 以编程方式访问接口。 🌐 To extend a plugin's interface within `./src/index.js|ts`, use the `bootstrap()` and `register()` [functions](/cms/configurations/functions) of the whole project, and access the interface programmatically with [getters](/cms/plugins-development/server-getters-usage).
在 ./src/index.js|ts 中扩展插件内容类型的示例 ```js title="./src/index.js|ts" module.exports = { register({ strapi }) { const contentTypeName = strapi.contentType('plugin::my-plugin.content-type-name') contentTypeName.attributes = { // Spread previous defined attributes ...contentTypeName.attributes, // Add new, or override attributes 'toto': { type: 'string', } } }, bootstrap({ strapi }) {}, }; ```
# 插件的服务器 API Source: https://docs.strapi.io/cms/plugins-development/server-api # 插件的服务器 API:概述 {#server-api-for-plugins-an-overview} 🌐 Server API for plugins: An overview Strapi 插件可以与 Strapi 应用的前端和后端进行交互。服务器 API 涵盖后端部分:它定义了插件在 Strapi 服务器上注册、暴露和执行的内容。服务器部分在入口文件中定义,该文件导出一个对象(或返回对象的函数)。该对象描述了插件对服务器的贡献内容。 🌐 A Strapi plugin can interact with both the back end and the front end of a Strapi application. The Server API covers the back-end part: it defines what the plugin registers, exposes, and executes on the Strapi server. The server part is defined in the entry file, which exports an object (or a function returning an object). That object describes what the plugin contributes to the server. 有关插件如何自定义管理面板界面的更多信息,请参阅 [Admin Panel API](/cms/plugins-development/admin-panel-api)。 🌐 For more information on how plugins can customize the admin panel UI, see [Admin Panel API](/cms/plugins-development/admin-panel-api). 从技术上讲,所有服务器代码都可以放在单一的入口文件中,但强烈建议将每个关注点拆分到各自的文件夹中,就像插件 SDK 生成的那样。本教程中的示例遵循了这种结构。 🌐 All server code can technically live in the single entry file, but splitting each concern into its own folder, as generated by the Plugin SDK, is strongly recommended. The examples in this documentation follow that structure. :::note Notes * 入口文件接受对象字面量或返回相同对象形状的函数。当使用函数形式时,Strapi 在加载插件模块时会使用 `{ env }`(而不是 `{ strapi }`)调用它。 * `config` 是一个配置对象,而不是可执行的生命周期钩子。与 `register()`、`bootstrap()` 或 `destroy()` 不同,它在插件生命周期中不会作为函数被调用。它在启动时加载,用于设置默认值和验证用户配置。有关更多信息,请参见 [服务器生命周期](/cms/plugins-development/server-lifecycle)。 ::: ## 可用操作 {#available-actions} 🌐 Available actions 服务器 API 让插件能够利用多个构建模块来定义其服务器端行为。 🌐 The Server API lets a plugin take advantage of several building blocks to define its server-side behavior. 使用下表查找与你的目标相匹配的能力: 🌐 Use the following table to find which capability matches your goal: | 目标 | 使用的参数 | 运行时间 | | --- | --- | --- | | 在服务器启动前运行代码 | [`register()`](/cms/plugins-development/server-lifecycle#register) | 在数据库和路由初始化之前 | | 在所有插件加载后运行代码 | [`bootstrap()`](/cms/plugins-development/server-lifecycle#bootstrap) | 在数据库、路由和权限初始化后 | | 在关闭时清理资源 | [`destroy()`](/cms/plugins-development/server-lifecycle#destroy) | 在关闭时 | | 使用默认值和验证定义插件选项 | [`config`](/cms/plugins-development/server-configuration) | 启动时加载 | | 声明插件内容类型 | [`contentTypes`](/cms/plugins-development/server-content-types) | 启动时加载 | | 公开 HTTP 端点 | [`routes`](/cms/plugins-development/server-routes) | 启动时加载 | | 处理 HTTP 请求 | [`controllers`](/cms/plugins-development/server-controllers-services#controllers) | 每个请求调用 | | 实现业务逻辑 | [`services`](/cms/plugins-development/server-controllers-services#services) | 从控制器或生命周期钩子调用 | | 在路由上强制执行访问规则 | [`policies`](/cms/plugins-development/server-policies-middlewares#policies) | 在控制器之前按每个请求评估 | | 拦截并修改请求/响应流程 | [`middlewares`](/cms/plugins-development/server-policies-middlewares#middlewares) | 附加在 `register()` 中或在路由配置中引用 | | 在运行时访问插件功能 | [获取器](/cms/plugins-development/server-getters-usage) | 任何生命周期或请求处理程序 |
以下卡片直接链接到各自的专页: 🌐 The following cards link directly to each dedicated page: :::strapi Backend customization 插件的路由、控制器、服务、策略和中间件遵循与标准 Strapi 应用中的[后端自定义](/cms/backend-customization)相同的约定。服务器 API 会自动将这些封装到插件命名空间中(有关 UID 和命名约定的详细信息,请参见[服务器内容类型](/cms/plugins-development/server-content-types#uids-and-naming-conventions))。 🌐 Plugin routes, controllers, services, policies, and middlewares follow the same conventions as [backend customization](/cms/backend-customization) in a standard Strapi application. The Server API wraps these into the plugin namespace automatically (see [server content types](/cms/plugins-development/server-content-types#uids-and-naming-conventions) for details on UIDs and naming conventions). ::: # 服务器配置 Source: https://docs.strapi.io/cms/plugins-development/server-configuration # 服务器 API:配置 {#server-api-configuration} 🌐 Server API: Configuration 一个插件可以从其[服务器入口文件](/cms/plugins-development/server-api#entry-file)暴露一个`config`对象。该对象定义默认的配置值,并验证从应用的`config/plugins.js|ts`文件加载的任何用户提供的覆盖配置。 🌐 A plugin can expose a `config` object from its [server entry file](/cms/plugins-development/server-api#entry-file). This object defines default configuration values and validates any user-provided overrides loaded from the application's `config/plugins.js|ts` file. 用户可以在应用的插件配置文件中覆盖这些值: 🌐 A user can override these values in the application's plugin configuration file: 在将默认设置与用户覆盖进行深度合并后,最终配置为 `{ enabled: true, maxItems: 25, endpoint: 'https://api.production.example.com' }`。 🌐 After deep-merging defaults with user overrides, the final config is `{ enabled: true, maxItems: 25, endpoint: 'https://api.production.example.com' }`. ## 运行时访问 {#runtime-access} 🌐 Runtime access 一旦插件被加载,其配置在任何可以访问 `strapi` 对象的地方都可用: 🌐 Once the plugin is loaded, its configuration is available anywhere the `strapi` object is accessible: ```js // Read one key const maxItems = strapi.plugin('my-plugin').config('maxItems'); ``` ```js // Read the entire plugin config object const pluginConfig = strapi.config.get('plugin::my-plugin'); ``` `strapi.plugin().config()` 和 `strapi.config.get()` 通常都在生命周期函数、控制器或服务中使用。 🌐 Both `strapi.plugin().config()` and `strapi.config.get()` are typically used inside lifecycle functions, controllers, or services. :::tip 使用 `yarn strapi console` 或 `npm run strapi console` 检查正在运行的 Strapi 实例的实时配置。 🌐 Use `yarn strapi console` or `npm run strapi console` to inspect the live configuration of a running Strapi instance. ::: ## 最佳实践 {#best-practices} 🌐 Best practices - **始终提供一个 `default`。** 没有默认值的插件会强制每个用户提供所有配置值,这会带来阻力。让每个选项都可选,并提供合理的默认值。 - **对环境感知的配置,请使用 `default` 的函数形式。** `({ env }) => ({...})` 形式让用户无需额外设置即可使用环境变量来驱动配置。普通对象形式适合真正的静态默认值。 - **保持验证简单明了。** `validator` 在启动时运行,在任何请求处理之前。抛出描述性错误,以便运算符确切知道问题出在哪里。例如,`'"maxItems" must be a positive number'` 比 `'Invalid config'` 更有用。 - **不要在插件配置中存储秘密。** 插件配置可以通过 `strapi.config` 在服务器端访问,如果处理不当,可能会通过日志、调试工具或自定义端点意外泄露。请直接在服务中使用环境变量,或通过 `default` 中的 `env` 助手读取这些值,而不要将原始凭据嵌入配置对象中。 - **在服务中读取配置,而不是内联读取。** 在服务方法内访问 `strapi.plugin('my-plugin').config('key')`,而不是在模块加载时访问,确保该值始终是最终合并的值,而不是在用户覆盖应用之前获取的快照。 # 服务器内容类型 Source: https://docs.strapi.io/cms/plugins-development/server-content-types # 服务器 API:内容类型 {#server-api-content-types} 🌐 Server API: Content-types 插件可以通过从 [服务器入口文件](/cms/plugins-development/server-api#entry-file) 导出一个 `contentTypes` 对象来声明自己的内容类型。Strapi 在启动时会在插件命名空间下注册这些内容类型,并通过文档服务 API 和内容类型注册表提供访问。 🌐 A plugin can declare its own content-types by exporting a `contentTypes` object from the [server entry file](/cms/plugins-development/server-api#entry-file). Strapi registers these content-types under the plugin namespace at startup and makes them available through the Document Service API and the content-type registry. ## UID 和命名规范 {#uids-and-naming-conventions} 🌐 UIDs and naming conventions 当注册插件内容类型时,Strapi 会从插件命名空间和在 `contentTypes` 导出中使用的键构建其运行时 UID: 🌐 When a plugin content-type is registered, Strapi builds its runtime UID from the plugin namespace and the key used in the `contentTypes` export: ``` plugin::. ``` 推荐的做法是设置 `content-types-key === info.singularName`。遵循这个做法可以使模式命名和运行时 UID 保持一致,并且更易于阅读。 🌐 The recommended convention is to set `content-types-key === info.singularName`. Following this convention keeps the schema naming and runtime UID aligned and easier to read. 当密钥匹配 `singularName`(推荐)时,生成的 UID 采用以下格式: 🌐 When the key matches `singularName` (recommended), the resulting UID follows this format: ``` plugin::. ``` 例如,一个名为 `my-plugin` 的插件,其内容类型的 `singularName` 是 `article`,导出键是 `article`,其 UID 是 `plugin::my-plugin.article`。 🌐 For example, a plugin named `my-plugin` with a content-type whose `singularName` is `article` and export key `article` has the UID `plugin::my-plugin.article`. :::warning 如果 `contentTypes` 键和 `info.singularName` 出现分歧,getter 和查询将使用从注册键构建的 UID(而不是从 `singularName` 构建)。这可能会在你的插件代码中引入命名不一致。 🌐 If the `contentTypes` key and `info.singularName` diverge, getters and queries use the UID built from the registered key (not from `singularName`). This can introduce naming inconsistencies across your plugin code. ::: 此 UID 在所有 API 中都保持一致使用: 🌐 This UID is used consistently across all APIs: | 用例 | 示例 || --- | --- || 通过文档服务查询 | `strapi.documents('plugin::my-plugin.article').findMany()` || 通过 getter 访问模式 | `strapi.contentType('plugin::my-plugin.article')` || 在路由处理程序中引用 | `handler: 'article.find'`(简短形式,通过插件注册表解析) || 传递给清理 API | `strapi.contentAPI.sanitize.output(data, schema, { auth })` | :::note 控制器、服务、策略和中间件对全局 getter 使用相同的 `plugin::.` UID 格式,但在插件级 API 中(例如路由 `handler` 和 `policies`)通过它们的短注册表键(例如 `'article'`)进行引用。详情请参见 [Getters & usage](/cms/plugins-development/server-getters-usage)。 ::: ## 运行时访问 {#access-at-runtime} 🌐 Access at runtime ### 使用文档服务 API 进行查询 {#querying-with-the-document-service-api} 🌐 Querying with the Document Service API 使用文档服务 API 从控制器、服务或生命周期钩子中查询插件内容类型: 🌐 Use the Document Service API to query plugin content-types from controllers, services, or lifecycle hooks: :::strapi Document Service API 有关可用方法和参数的完整列表,请参见 [文档服务 API](/cms/api/document-service)。 🌐 For the full list of available methods and parameters, see the [Document Service API](/cms/api/document-service). ::: ### 访问架构 {#accessing-the-schema} 🌐 Accessing the schema 使用内容类型获取器来获取模式对象,例如将其传递给清理 API: 🌐 Use the content-type getter to retrieve the schema object, for example to pass it to the sanitization API: ## 最佳实践 {#best-practices} 🌐 Best practices - **将导出键精确匹配为 `info.singularName`。** 这样可以保持命名的可读性和一致性。在运行时,Strapi 会从插件命名空间下 `contentTypes` 映射的键中派生插件内容类型 UID。即使注册仍然成功,不匹配也可能会产生混乱的 UID 和维护问题。 - **使用 `collectionName` 避免表名冲突。** `collectionName` 字段用于设置数据库表的名称。将其前缀加上插件名称(例如 `my_plugin_articles`),以避免与应用内容类型或其他插件发生冲突。 - **将内容类型的模式保存在自己的文件中。** 在名为 `singularName` 的子文件夹中,为每个模式定义一个专用的 `schema.json` 文件(例如,`content-types/article/schema.json`)。这与插件 SDK 生成的结构相匹配,并保持索引文件的可读性。 - **仅在需要时启用 `draftAndPublish`。** 草稿和发布为内容类型添加了一个发布工作流程。仅在插件的使用场景需要时启用它,因为它会增加查询和内容管理的复杂性。 # 服务器控制器和服务 Source: https://docs.strapi.io/cms/plugins-development/server-controllers-services # 服务器 API:控制器和服务 {#server-api-controllers--services} 🌐 Server API: Controllers & services 控制器和服务是插件服务器中处理请求和业务逻辑的两个构建模块。它们在职责分离上协同工作:控制器负责 HTTP 层,服务负责字段层: 🌐 Controllers and services are the 2 building blocks that handle request processing and business logic in a plugin server. They work together in a clear separation of concerns: controllers own the HTTP layer, services own the domain layer: | 目标 | 使用 || --- | --- || 接收 `ctx`,读取请求,设置响应 | [控制器](#controllers) || 查询数据库或应用业务规则 | [服务](#services) || 在多个控制器或生命周期钩子中重用逻辑 | [服务](#services) || 作为请求的一部分调用外部 API | [服务](#services) | ### 消毒 {#sanitization} 🌐 Sanitization 当你的插件公开内容 API 路由时,在返回查询参数和输出数据之前,请对其进行清理。这可以防止泄露私有字段或绕过访问规则。 🌐 When your plugin exposes Content API routes, sanitize query parameters and output data before returning them. This prevents leaking private fields or bypassing access rules. 插件控制器是普通的工厂函数,并不像 Strapi 核心中那样继承 `createCoreController`(详情请参见 [后端自定义](/cms/backend-customization/controllers))。这意味着 `this.sanitizeQuery` 和 `this.sanitizeOutput` 简写不可用。请直接使用 `strapi.contentAPI.sanitize`,并显式传入内容类型的架构: 🌐 Plugin controllers are plain factory functions and do not extend `createCoreController` like in the Strapi core (see [backend customization](/cms/backend-customization/controllers) for details). This means the `this.sanitizeQuery` and `this.sanitizeOutput` shorthands are not available. Use `strapi.contentAPI.sanitize` directly instead, passing the content-type schema explicitly: :::strapi Backend customization 有关完整的清理和验证参考,包括 `sanitizeInput`、`validateQuery` 和 `validateInput`,请参见 [Controllers](/cms/backend-customization/controllers#sanitize-validate-custom-controllers)。 🌐 For the full sanitization and validation reference, including `sanitizeInput`, `validateQuery`, and `validateInput`, see [Controllers](/cms/backend-customization/controllers#sanitize-validate-custom-controllers). ::: ## 服务 {#services} 🌐 Services 服务是一个工厂函数,它接收 `{ strapi }` 并返回一个具有命名方法的对象,或一个普通对象;像 [controllers](#declaration) 一样,Strapi 在运行时解析两者。服务包含由控制器、生命周期钩子或其他服务调用的业务逻辑。 🌐 A service is a factory function that receives `{ strapi }` and returns an object of named methods, or a plain object; like [controllers](#declaration), Strapi resolves both at runtime. Services hold business logic called from controllers, lifecycle hooks, or other services. ### 声明 {#declaration-1} 🌐 Declaration :::caution TypeScript service typing `services` 在当前的 `ServerObject` TypeScript 接口 (`@strapi/types`) 中被类型化为 `unknown`。这意味着 `strapi.plugin('my-plugin').service('article')` 返回 `unknown`,并且调用带有类型安全的方法时需要进行类型转换。对于完全类型化的服务调用,请显式定义并导出服务类型,并在调用处进行类型转换。 ::: :::strapi Document Service API 服务通过[文档服务 API](/cms/api/document-service)与内容类型进行交互,该 API 记录了可用方法和参数的完整列表。 🌐 Services interact with content-types through the [Document Service API](/cms/api/document-service), which documents the full list of available methods and parameters. ::: ## 端到端示例 {#end-to-end-example} 🌐 End-to-end example 以下示例展示了针对一个简单文章资源,跨路由、控制器和服务的完整请求流程。 🌐 The following example shows the complete request flow across routes, a controller, and a service for a simple article resource. ## 最佳实践 {#best-practices} 🌐 Best practices - **保持控制器简洁。** 控制器操作应该做三件事:接收 `ctx`,委托给服务,并设置响应。业务逻辑、数据库调用以及条件分支都应该放在服务中。 - **每个资源一个服务。** 按它们管理的资源组织服务(例如 `article`、`comment`、`settings`),而不是按操作类型组织。这可以让每个文件集中并且易于测试。 - **在服务中使用文档服务 API,而不是在控制器中。** 在控制器中直接调用 `strapi.documents(...)` 会绕过服务层,使逻辑难以复用。将所有文档服务调用放在服务中。 - **清理内容 API 响应。** 在公开内容 API 路由时,返回数据之前使用 `strapi.contentAPI.sanitize.output()`。跳过清理可能会将私有字段泄露给终端用户。管理员路由不受相同内容类型字段可见性规则的限制,但对它们进行清理也是无害的。 - **在 TypeScript 中显式地转换服务类型。** 在 `@strapi/types` 中 `services` 还未强类型化之前,在每个调用点将 `strapi.plugin('my-plugin').service('my-service')` 的返回值转换为服务接口。避免在整个代码库中使用 `any`。 # 服务器获取器及使用 Source: https://docs.strapi.io/cms/plugins-development/server-getters-usage # 服务器 API:获取器与使用 {#server-api-getters--usage} 🌐 Server API: Getters & usage 插件服务器资源,例如控制器、服务、策略、中间件和内容类型,可以通过 `strapi` 实例从任何服务器端位置访问:其他插件、生命周期钩子、应用控制器或自定义脚本。路由和配置使用专用的 API — 请参见下面的 [getter 参考](#full-getter-reference)。 🌐 Plugin server resources, such as controllers, services, policies, middlewares, and content-types, are accessible from any server-side location through the `strapi` instance: other plugins, lifecycle hooks, application controllers, or custom scripts. Routes and configuration use dedicated APIs — see the [getter reference](#full-getter-reference) below. ### 从 bootstrap 调用插件服务 {#calling-a-plugin-service-from-bootstrap} 🌐 Calling a plugin service from bootstrap 在 `bootstrap()` 中调用的服务可以访问完整的 `strapi` 实例,包括其他插件的服务: 🌐 Services called in `bootstrap()` have access to the full `strapi` instance, including other plugins' services: ### 在插件之间或从应用代码中调用 {#calling-across-plugins-or-from-application-code} 🌐 Calling across plugins or from application code 从应用级别的控制器或服务(在插件外部),或者从另一个插件调用时,使用完整 UID 的全局获取器通常更清晰: 🌐 From application-level controllers or services (outside the plugin), or when calling from another plugin, global getters using the full UID are often clearer: ### 在运行时读取插件配置 {#reading-plugin-configuration-at-runtime} 🌐 Reading plugin configuration at runtime ```js // Read a single key const maxItems = strapi.plugin('todo').config('maxItems'); ``` ```js // Read the full config object const todoConfig = strapi.config.get('plugin::todo'); ``` ```js // Read a nested key const endpoint = strapi.config.get('plugin::todo.endpoint'); ``` :::note `strapi.plugin('my-plugin').config('key')` 读取合并后的配置(用户覆盖应用在插件默认值之上)。这是在插件代码中读取配置的推荐方式。有关插件配置如何声明和合并,请参阅 [服务器配置](/cms/plugins-development/server-configuration)。 ::: ### 访问内容类型架构 {#accessing-a-content-type-schema} 🌐 Accessing a content-type schema 当你需要 schema 对象时使用 content-type 获取器,例如将其传递给清理 API: 🌐 Use the content-type getter when you need the schema object, for example to pass it to the sanitization API: ## 常见错误 {#common-errors} 🌐 Common errors - **路由处理程序与控制器键命名不匹配。** 如果你的路由声明了 `handler: 'task.find'`,你的控制器索引必须导出一个名为 `task` 的键,并且该控制器必须有一个名为 `find` 的方法。当路由匹配时,如果不匹配会抛出运行时错误。 - **滥用策略上下文参数。** 策略函数的第一个参数是一个策略上下文对象,而不是原生的 Koa `ctx`。它封装了请求上下文,但提供了不同的接口。在你的代码中将它命名为 `ctx` 不会导致错误,但将其当作 Koa 上下文处理(例如,调用 `ctx.body` 或 `ctx.status`)将无法按预期工作。使用 `policyContext.state` 访问认证状态,并调用 `return false` 或抛出 `PolicyError` 来阻止请求。 - **在模块加载时调用服务。** 当模块首次加载时,`strapi` 对象尚未初始化。始终在函数体内调用 getter。不要在模块文件的顶层调用它们。 - **在全局 getter 中使用不完整的 UID。** `strapi.service('todo.task')` 不是有效的插件 UID。请使用完整的 `plugin::todo.task` 形式。如果没有正确的命名空间,服务调用将在运行时失败或返回 `undefined`。 | 范围 | 示例 UID | | --- | --- | | 插件服务 | `plugin::todo.task` | | API 服务 | `api::project.project` | ## 最佳实践 {#best-practices} 🌐 Best practices - **在你自己的插件中优先使用顶层 getter。** 当两者都在同一个插件中时,`strapi.plugin('my-plugin').service('task')` 比全局形式更易读。 - **在应用代码和跨插件调用中使用全局 getter。** 当从 `src/api/` 调用或从另一个插件调用时,使用完整的 UID `plugin::todo.task` 可以明确依赖,并且更容易搜索。 - **在使用服务时访问服务,而不是在声明时。** 避免在模块初始化时在闭包中捕获服务引用。始终在调用时使用 getter 解析它们,以确保 Strapi 完全加载。 # 服务器生命周期 Source: https://docs.strapi.io/cms/plugins-development/server-lifecycle # 服务器 API:生命周期 {#server-api-lifecycle} 🌐 Server API: Lifecycle 生命周期函数控制插件的服务器端逻辑在 Strapi 应用启动和关闭过程中何时运行。它们与路由、控制器、服务和其他服务器模块一起从[服务器入口文件](/cms/plugins-development/server-api#entry-file)导出。 🌐 Lifecycle functions control when your plugin's server-side logic runs during the Strapi application startup and shutdown sequence. They are exported from the [server entry file](/cms/plugins-development/server-api#entry-file) alongside routes, controllers, services, and other server blocks. ## bootstrap() **类型:** `Function` `bootstrap()` 在模块生命周期注册(插件/API)、数据库初始化、路由初始化和内容 API 操作注册之后运行。 使用 `bootstrap()` 来: 🌐 Use `bootstrap()` to: - 用初始数据填充数据库 - 使用 `strapi.service('admin::permission').actionProvider.registerMany(...)` 注册管理员 RBAC 操作 - 注册 cron 任务 - 订阅数据库生命周期事件 - 从你的插件或其他插件调用服务 - 设置需要先注册其他插件的跨插件集成 ## destroy() **类型:** `Function` `destroy()` 在 Strapi 实例关闭时调用。这是可选的。只有在你的插件持有需要显式清理的资源时才实现它。 使用 `destroy()` 来: 🌐 Use `destroy()` to: - 关闭外部连接(数据库、消息队列、WebSocket 服务器) - 在 `bootstrap()` 中清除间隔或超时 - 移除在插件生命周期内注册的事件监听器 ## 最佳实践 {#best-practices} 🌐 Best practices - **保持 `register()` 轻量化。** 它在完全初始化之前运行。 - **使用 `bootstrap()` 进行数据库读写。** 数据库在引导阶段初始化,而不是在注册阶段。任何对 `strapi.documents()` 的调用或查询数据库的服务都应放在 `bootstrap()` 中。 - **在 `bootstrap()` 中注册管理员 RBAC 操作。** 在 `bootstrap()` 中使用 `strapi.service('admin::permission').actionProvider.registerMany(...)`。这是在权限服务可用时。内容 API 操作在同一阶段由 Strapi 自动注册。 - **始终将资源创建与 `destroy()` 配对。** 如果你的插件在 `bootstrap()` 中打开连接、注册全局定时器或附加进程监听器,请实现 `destroy()` 来清理这些资源。这可以防止在测试和优雅重启期间发生资源泄漏。 - **避免 `register()` 中插件之间的强依赖。** 在注册时,其他插件的注册顺序无法保证。依赖于另一个插件已初始化的跨插件调用应放在 `bootstrap()` 中。 - **优先使用服务而非内联逻辑。** 将非平凡的启动逻辑移入专用的服务方法(例如 `strapi.plugin('my-plugin').service('setup').initialize()`)。这样可以保持生命周期文件的可读性,同时使逻辑易于测试。 # 服务器策略和中间件 Source: https://docs.strapi.io/cms/plugins-development/server-policies-middlewares # 服务器 API:策略和中间件 {#server-api-policies--middlewares} 🌐 Server API: Policies & middlewares 策略和中间件是插件服务器中拦截请求的两种机制。策略决定请求是否应该继续。中间件决定它如何被处理。 🌐 Policies and middlewares are the two mechanisms for intercepting requests in a plugin server. Policies decide whether a request should proceed. Middlewares shape how it is processed. ### 在路由中的使用 {#usage-in-routes} 🌐 Usage in routes 一旦声明,可以使用 `plugin::my-plugin.policy-name` 命名空间从路由中引用插件策略: 🌐 Once declared, reference a plugin policy from a route using the `plugin::my-plugin.policy-name` namespace: :::caution Policy return values 返回 `false` 会导致 Strapi 发送 `403 Forbidden` 响应。返回空 (`undefined`) 被视为允许(允许),而不是阻止。始终明确返回 `true` 或 `false`。抛出错误会导致 Strapi 发送 `500` 响应,除非你抛出 Strapi HTTP 错误类(例如 `new errors.PolicyError(...)`、`new errors.ForbiddenError(...)` 或 `new errors.UnauthorizedError(...)`)。 🌐 Returning `false` causes Strapi to send a `403 Forbidden` response. Returning nothing (`undefined`) is treated as permissive (allowed), not as a block. Always return `true` or `false` explicitly. Throwing an error causes Strapi to send a `500` response unless you throw a Strapi HTTP error class (e.g., `new errors.PolicyError(...)`, `new errors.ForbiddenError(...)`, or `new errors.UnauthorizedError(...)`). ::: :::strapi Backend customization 有关包括 GraphQL 支持和 `policyContext` API 在内的完整政策参考,请参阅 [Policies](/cms/backend-customization/policies)。 🌐 For the full policy reference including GraphQL support and the `policyContext` API, see [Policies](/cms/backend-customization/policies). ::: ## 中间件 {#middlewares} 🌐 Middlewares 中间件是一个 Koa 风格的函数,用于封装请求/响应周期。与 [策略](#policies)(它们是通过/不通过的守卫)不同,中间件可以在请求到达控制器之前读取和修改请求,并在控制器执行后修改响应。 🌐 A middleware is a Koa-style function that wraps the request/response cycle. Unlike [policies](#policies) (which are pass/fail guards), middlewares can read and modify the request before it reaches the controller, and modify the response after the controller has executed. 插件可以通过两种方式导出中间件: 🌐 Plugins can export middlewares in 2 ways: - 作为**路由级中间件**,在服务器入口文件的 `middlewares` 导出中声明,并在路由 `config.middlewares` 中引用 - 作为**服务器级中间件**,通过 `strapi.server.use()` 在 `register()` 中直接注册到 Strapi HTTP 服务器上 ### 路由级中间件 {#route-level-middlewares} 🌐 Route-level middlewares 路由级中间件作用于特定路由,并且声明方式类似于策略:作为命名工厂函数的对象,然后在路由配置中引用。 🌐 Route-level middlewares are scoped to a specific route and are declared like policies: as an object of named factory functions, then referenced in the route config. 注意这个两级签名:外层函数接收 `(config, { strapi })` 并返回实际的 Koa 中间件 `async (ctx, next) => {}`。这允许 Strapi 将每条路由的配置传递给该函数。 🌐 Note the two-level signature: the outer function receives `(config, { strapi })` and returns the actual Koa middleware `async (ctx, next) => {}`. This allows Strapi to pass per-route configuration to the function. :::note - `middlewares` 从插件中导出中间件函数,以便在路由配置中引用和重用。 - `strapi.server.use(...)` 将一个中间件附加到全局服务器管道上。 - 中间件的执行是基于请求的:一旦附加到路由或服务器管道,它会在每个匹配的请求中运行。 ::: 在路由中使用与策略相同的 `plugin::my-plugin.middleware-name` 命名空间引用路由级中间件: 🌐 Reference a route-level middleware in a route using the same `plugin::my-plugin.middleware-name` namespace as policies: ### 服务器级中间件 {#server-level-middlewares} 🌐 Server-level middlewares 服务器级中间件直接注册在 Strapi HTTP 服务器上,并且针对每个请求运行,而不仅仅是插件路由。在 `register()` 中使用 `strapi.server.use()` 注册它: 🌐 A server-level middleware is registered on the Strapi HTTP server directly and runs for every request, not just plugin routes. Register it in `register()` using `strapi.server.use()`: :::caution 服务器级中间件会影响所有插件和应用本身的所有路由,而不仅仅是你插件的路由。一个抛出异常或从未调用 `next()` 的服务器级中间件会破坏服务器上的每一个请求,而不仅仅是你插件的端点。当关心的问题仅涉及你插件的端点时,请使用路由级中间件。 🌐 Server-level middlewares affect all routes across all plugins and the application itself, not just your plugin's routes. A server-level middleware that throws or never calls `next()` will break every request on the server, not just your plugin's endpoints. Use route-level middlewares when the concern is specific to your plugin's endpoints. ::: :::note Version/runtime behavior 对于路由声明,验证接受形状为 `{ name, options }` 的对象条目,用于 `policies` 和 `middlewares`(见 `services/server/routing.ts`)。 🌐 For route declarations, validation accepts object entries shaped as `{ name, options }` for both `policies` and `middlewares` (see `services/server/routing.ts`). 在运行时,一些内部仍然在中间件解析器(`services/server/middleware.ts`)中引用 `{ resolve, config }` 支持,但标准路由文件中的路由验证不接受该形状。 🌐 At runtime, some internals still reference `{ resolve, config }` support in the middleware resolver (`services/server/middleware.ts`), but that shape is not accepted by route validation in standard route files. 为了避免验证错误,请在路由配置中使用 `{ name, options }`。 🌐 To avoid validation errors, use `{ name, options }` in route configurations. ::: :::strapi Backend customization 有关完整的中间件参考,请参见 [中间件](/cms/backend-customization/middlewares)。 🌐 For the full middleware reference, see [Middlewares](/cms/backend-customization/middlewares). ::: ## 最佳实践 {#best-practices} 🌐 Best practices - **在策略中使用 `policyContext`,而不是 `ctx`。** 策略的第一个参数是 `policyContext`,它是 Koa 上下文的一个封装。正确使用它可以确保策略在 REST 和 GraphQL 解析器中都能正常工作。 - **明确地从策略中返回。** 返回 `undefined` 的策略被视为允许(允许)的策略。要允许请始终返回 `true`,要拒绝请始终返回 `false`。如果意图是阻止请求,请勿隐式返回。 - **优先使用路由级中间件而非服务器级中间件。** 服务器级中间件会在整个 Strapi 服务器的每个请求上运行。除非该行为确实适用于所有流量,否则将中间件范围限制在插件路由上。 - **在中间件中始终调用 `await next()`。** 忘记 `next()` 意味着请求链被中断,控制器永远不会执行,导致请求挂起且没有响应。 - **使用 `options` 来实现可重用的策略。** 当相同的策略逻辑在不同路由中需要不同的参数(例如,必需的角色名称)时,可以从路由的 `{ name, options }` 对象中传递这些参数。这些值会在策略函数的 `config` 参数中接收。这可以避免重复类似的策略。 # 服务器路由 Source: https://docs.strapi.io/cms/plugins-development/server-routes # 服务器 API:路由 {#server-api-routes} 🌐 Server API: Routes 路由会公开你的插件的 HTTP 端点,并将传入请求映射到控制器操作。它们从 [服务器入口文件](/cms/plugins-development/server-api#entry-file) 导出,作为一个 `routes` 值。 🌐 Routes expose your plugin's HTTP endpoints and map incoming requests to controller actions. They are exported from the [server entry file](/cms/plugins-development/server-api#entry-file) as a `routes` value. ### 命名路由格式 {#named-router-format} 🌐 Named router format 使用命名路由格式时,使用具有命名键(`admin`、`content-api` 或任何自定义名称)的对象来声明单独的路由组。每个组都是一个路由对象,包含 `type`、可选的 `prefix` 和一个 `routes` 数组。当你的插件同时暴露管理和内容 API 路由时使用此格式。 🌐 With the named router format, use an object with named keys (`admin`, `content-api`, or any custom name) to declare separate router groups. Each group is a router object with a `type`, optional `prefix`, and a `routes` array. Use this format when your plugin exposes both admin and Content API routes. ### 工厂回调格式 {#factory-callback-format} 🌐 Factory callback format 对于需要在路由配置时访问 `strapi` 实例的高级情况(例如,用于构建动态路径或根据配置有条件地包含路由),你可以导出一个工厂回调。 🌐 For advanced cases where you need access to the `strapi` instance at route configuration time (for example, to build dynamic paths or conditionally include routes based on configuration), you can export a factory callback. :::note 工厂回调必须附加到命名路由条目(例如 `admin` 或 `content-api`),而不是作为 `routes/index` 的根导出。 🌐 The factory callback must be attached to a named route entry (such as `admin` or `content-api`), not exported as the root of `routes/index`. `module.exports = ({ strapi }) => ({ ... })` 在根级别不是有效的格式。 ::: 有关 Strapi 在注册时自动添加的内容的详细信息,请参见 [Strapi 应用的默认值](#defaults-applied-by-strapi)。 🌐 For details on what Strapi adds automatically at registration time, see [Defaults applied by Strapi](#defaults-applied-by-strapi). ## Strapi 应用的默认设置 {#defaults-applied-by-strapi} 🌐 Defaults applied by Strapi 当 Strapi 注册插件路由时,它会自动应用以下默认设置: 🌐 When Strapi registers plugin routes, it applies the following defaults automatically: | 属性 | 默认值 | 说明 || --- | --- | --- || `type` | `'admin'` | 在使用数组格式时应用,或者在命名格式中路由对象省略 `type` 时应用 || `prefix` | `'/'` | 在使用数组格式时应用,或者在路由对象中省略 `prefix` 时应用 || `config.auth.scope` | `['plugin::.']` | 仅对字符串处理器自动生成,使用 `defaultsDeep`,以避免覆盖现有值 | 以下两条声明是等效的。Strapi 会自动应用上表中的默认值: 🌐 The following 2 declarations are equivalent. Strapi applies the defaults from the table above automatically: ## 路由配置参考 {#route-configuration-reference} 🌐 Route configuration reference 每条路由都可以接受一个可选的 `config` 对象,该对象具有以下属性: 🌐 Each route accepts an optional `config` object with the following properties: ### `policies` **类型:** `Array` 在控制器动作之前运行的策略。每一项要么是策略名称字符串,要么是内联函数,或者是包含必需的 `name` 和可选的 `options` 的对象。 🌐 Policies to run before the controller action. Each item is either a policy name string, an inline function, or an object with required `name` and optional `options`. `options` 对象将原样传递给策略函数的第二个参数(策略签名中的 `config`)。该对象的形状取决于策略。 🌐 The `options` object is passed as-is to the policy function's second argument (`config` in policy signatures). The shape of this object depends on the policy. 插件政策被引用为 `plugin::my-plugin.policy-name`。 🌐 Plugin policies are referenced as `plugin::my-plugin.policy-name`. ### `middlewares` **类型:** `Array` 要应用到此路由的中间件。每个项目可以是中间件名称字符串、内联函数或具有以下属性的对象: 🌐 Middlewares to apply to this route. Each item is a middleware name string, an inline function, or an object with: - `name`:已注册的中间件名称, - `options`(可选):中间件选项。 :::note Route middlewares vs. global server middlewares 在路由验证时,Strapi 会根据 `{ name: string; options?: object }` 验证中间件/策略对象(参见 `services/server/routing.ts`)。 🌐 At route validation time, Strapi validates middleware/policy objects against `{ name: string; options?: object }` (see `services/server/routing.ts`). 中间件解析器(`services/server/middleware.ts`)仍然包含对 `{ resolve, config }` 对象的运行时支持,但在标准插件路由声明解析之前,此形状会被路由验证拒绝。 🌐 The middleware resolver (`services/server/middleware.ts`) still contains runtime support for `{ resolve, config }` objects, but this shape is rejected by route validation before resolution for standard plugin route declarations. 在路由配置中使用 `{ name, options }` 以兼容验证。 🌐 Use `{ name, options }` in route configs for compatibility with validation. ::: ### `auth` **类型:** `false | { scope: string[]; strategies?: string[] }` 设置为 `false` 以使路由公开。传递一个对象以定义认证范围,并可选择自定义认证策略。 🌐 Set to `false` to make the route public. Pass an object to define the auth scope and, optionally, custom auth strategies. 在运行时,当 `auth` 是对象时,必须存在 `scope`。 🌐 At runtime, `scope` must be present when `auth` is an object. :::note 对于**字符串处理器**(例如,`handler: 'article.find'`),Strapi 会自动注入一个默认的 `config.auth.scope` 值,因此像 `auth: {}` 这样的模式仍然可以工作。 🌐 For **string handlers** (for example, `handler: 'article.find'`), Strapi auto-injects a default `config.auth.scope` value, so patterns such as `auth: {}` can still work. 对于**非字符串处理器**(内联函数),不要假设自动作用域注入。当 `auth` 是对象时,必须显式定义 `config.auth.scope`。 🌐 For **non-string handlers** (inline functions), do not assume auto-scope injection. Define `config.auth.scope` explicitly when `auth` is an object. ::: :::caution 在管理员路由上设置 `auth: false` 几乎从来不是故意的:它会使该端点暴露给未认证的请求。 🌐 Setting `auth: false` on an admin route is almost never intentional: it exposes the endpoint to unauthenticated requests. ::: :::strapi General backend customization examples 有关包含策略、公共路由、动态 URL 参数和路径中正则表达式的配置示例,请参见 [Routes](/cms/backend-customization/routes)。 🌐 For configuration examples including policies, public routes, dynamic URL parameters, and regular expressions in paths, see [Routes](/cms/backend-customization/routes). ::: ## 最佳实践 {#best-practices} 🌐 Best practices - **在同时公开管理和内容 API 端点时,请使用命名路由格式。** 这样可以明确每个路由的意图,避免依赖可能令人意外的 `type` 默认值。 - **保持 `handler` 为字符串。** 字符串处理程序会自动生成授权范围,而函数处理程序不会。除非你设置了 `config.auth: false`,否则身份验证仍会针对字符串和函数处理程序运行,但只有字符串处理程序会自动获得 `config.auth.scope`。如果你使用函数处理程序并且需要路由级权限范围,请显式定义 `config.auth.scope`。 - **将策略的作用范围限定到其命名空间。** 在路由中引用插件策略时,请使用完整的 `plugin::my-plugin.policy-name` 形式。如果应用中其他地方存在同名的短名策略,这可以避免歧义。 - **不要在管理路由上禁用身份验证。** 管理路由默认需要管理员身份验证。在管理路由上禁用身份验证会使其暴露给未经过身份验证的请求,这几乎从来都不是有意为之。 - **将相关的路由分组到专用文件中。** 随着插件的增长,单个路由索引文件变得难以导航。按资源拆分(例如,`routes/article.js`、`routes/comment.js`),并从 `routes/index.js` 重新导出。 # 文档插件 Source: https://docs.strapi.io/cms/plugins/documentation # 文档插件 {#documentation-plugin} 🌐 Documentation plugin 文档插件可以自动化生成你的 API 文档。它基本上会生成一个 Swagger 文件。它遵循 :::caution Unmaintained plugin 文档插件未主动维护,可能无法与 Strapi 5 兼容。 🌐 The Documentation plugin is not actively maintained and may not work with Strapi 5. ::: 安装插件后,启动 Strapi 会生成 API 文档。 🌐 Once the plugin is installed, starting Strapi generates the API documentation. ## 配置 {#configuration} 🌐 Configuration 文档插件的大多数配置选项都是通过你的 Strapi 项目的代码来处理的。在管理面板中可以使用一些设置。 🌐 Most configuration options for the Documentation plugin are handled via your Strapi project's code. A few settings are available in the admin panel. ### 管理面板设置 {#admin-panel-settings} 🌐 Admin panel settings 文档插件会影响管理面板的多个部分。以下表格列出了在安装该插件后,添加到 Strapi 应用中的所有附加选项和设置: 🌐 The Documentation plugin affects multiple parts of the admin panel. The following table lists all the additional options and settings that are added to a Strapi application once the plugin has been installed: | 受影响的部分 | 选项和设置 | |------------------|-------------------------------------------------------------| | 文档 |
    在主导航中添加了一个新的文档选项 ,该选项显示一个带有按钮的面板,用于 打开和 重新生成文档。
| | 设置 |
  • 新增“文档插件”设置部分,用于控制文档端点是否为私有(参见[访问限制](#restrict-access))。
    👉 路径提示: *设置 > 文档插件*

  • 启用基于角色的访问控制,用于访问、更新、删除和重新生成文档。管理员可以在*插件*标签和*设置*标签中为不同类型的用户授权不同的访问级别(参见[用户与权限文档](/cms/features/users-permissions))。
    👉 路径提示: *设置 > 管理面板 > 角色*
| #### 限制访问你的 API 文档 {#restrict-access} 🌐 Restricting access to your API documentation 默认情况下,任何人都可以访问你的 API 文档。 🌐 By default, your API documentation will be accessible by anyone. 要限制 API 文档访问,请在管理面板中启用 **受限访问** 选项: 🌐 To restrict API documentation access, enable the **Restricted Access** option from the admin panel: 1. 在管理员面板的主导航中,导航到 *设置*。 2. 选择 **文档**。 3. 切换 **受限访问** 到 `ON`。 4. 在 `password` 输入框中定义一个密码。 5. 保存设置。 ### 基于代码的配置 {#code-based-configuration} 🌐 Code-based configuration 要配置文档插件,请在 `src/extensions/documentation/config` 文件夹中创建一个 `settings.json` 文件。在此文件中,你可以指定所有环境变量、许可证、外部文档链接,以及 中列出的所有条目。 以下是配置示例: 🌐 The following is an example configuration: ```json title="src/extensions/documentation/config/settings.json" { "openapi": "3.0.0", "info": { "version": "1.0.0", "title": "DOCUMENTATION", "description": "", "termsOfService": "YOUR_TERMS_OF_SERVICE_URL", "contact": { "name": "TEAM", "email": "contact-email@something.io", "url": "mywebsite.io" }, "license": { "name": "Apache 2.0", "url": "https://www.apache.org/licenses/LICENSE-2.0.html" } }, "x-strapi-config": { "plugins": ["upload", "users-permissions"], "path": "/documentation" }, "servers": [ { "url": "http://localhost:1337/api", "description": "Development server" } ], "externalDocs": { "description": "Find out more", "url": "https://strapi.nodejs.cn/developer-docs/latest/getting-started/introduction.html" }, "security": [ { "bearerAuth": [] } ] } ``` :::tip 如果你需要添加自定义键,请在其前加上 `x-` 前缀(例如,`x-strapi-something`)。 🌐 If you need to add a custom key, prefix it by `x-` (e.g., `x-strapi-something`). ::: #### 创建文档的新版本 {#create-a-new-version-of-the-documentation} 🌐 Creating a new version of the documentation 要创建新版本,请更改 `settings.json` 文件中的 `info.version` 键: 🌐 To create a new version, change the `info.version` key in the `settings.json` file: ```json title="src/extensions/documentation/config/settings.json" { "info": { "version": "2.0.0" } } ``` 这将自动创建一个新版本。 🌐 This will automatically create a new version. #### 定义需要生成文档的插件 {#define-which-plugins} 🌐 Defining which plugins need documentation generated 如果你希望插件被包含在文档生成中,它们应该被包含在 `x-strapi-config` 对象中的 `plugins` 数组中。默认情况下,该数组使用 `["upload", "users-permissions"]` 初始化: 🌐 If you want plugins to be included in documentation generation, they should be included in the `plugins` array in the `x-strapi-config` object. By default, the array is initialized with `["upload", "users-permissions"]`: ```json title="src/extensions/documentation/config/settings.json" { "x-strapi-config": { "plugins": ["upload", "users-permissions"] } } ``` 要添加更多插件(例如你的自定义插件),请将其名称添加到数组中。 🌐 To add more plugins, such as your custom plugins, add their name to the array. 如果你不希望在文档生成中包含插件,请提供一个空数组(即 `plugins: []`)。 🌐 If you do not want plugins to be included in documentation generation, provide an empty array (i.e., `plugins: []`). #### 覆盖生成的文档 {#overriding-the-generated-documentation} 🌐 Overriding the generated documentation 文档插件提供了3种方法来覆盖生成的文档:["excludeFromGeneration"](#excluding-from-generation)、["registerOverride"](#register-override) 和 ["mutateDocumentation"](#mutate-documentation)。 🌐 The Documentation plugins comes with 3 methods to override the generated documentation: [`excludeFromGeneration`](#excluding-from-generation), [`registerOverride`](#register-override), and [`mutateDocumentation`](#mutate-documentation). ##### excludeFromGeneration() {#从生成中排除} 🌐 excludeFromGeneration() 要排除某些 API 或插件不被生成,请使用在应用或插件的 [`register` 生命周期](/cms/plugins-development/admin-panel-api#register) 中文档插件的 `override` 服务中找到的 `excludeFromGeneration`。 🌐 To exclude certain APIs or plugins from being generated, use the `excludeFromGeneration` found on the documentation plugin’s `override` service in your application or plugin's [`register` lifecycle](/cms/plugins-development/admin-panel-api#register). :::note `excludeFromGeneration` 提供了对生成内容的更精细控制。 例如,pluginA 可能会创建几个新的 API,而 pluginB 可能只想为其中的一些 API 生成文档。在这种情况下,pluginB 仍然可以通过仅排除它不需要的部分,从而受益于所生成的所需文档。 🌐 For example, pluginA might create several new APIs while pluginB may only want to generate documentation for some of those APIs. In that case, pluginB could still benefit from the generated documentation it does need by excluding only what it does not need. ::: ***** | 参数 | 类型 | 描述 || --- | --- | --- || `api` | 字符串或字符串数组 | 要排除的 API/插件的名称,或名称列表 | ```js title="Application or plugin register lifecycle" module.exports = { register({ strapi }) { strapi .plugin("documentation") .service("override") .excludeFromGeneration("restaurant"); // or several strapi .plugin("documentation") .service("override") .excludeFromGeneration(["address", "upload"]); } } ``` ##### registerOverride() {#register-override} 如果文档插件无法生成你期望的内容,则可以替换已生成的内容。 🌐 If the Documentation plugin fails to generate what you expect, it is possible to replace what has been generated. Documentation 插件提供了一个 API,允许你替换为以下 OpenAPI 根级别键生成的内容:`paths`、`tags`、`components`。 🌐 The Documentation plugin exposes an API that allows you to replace what was generated for the following OpenAPI root level keys: `paths`, `tags`, `components` . 要提供覆盖,请在你的应用或插件的 [`register` 生命周期](/cms/plugins-development/admin-panel-api#register) 中,使用文档插件 `override` 服务中的 `registerOverride` 函数。 🌐 To provide an override, use the `registerOverride` function found on the Documentation plugin’s `override` service in your application or plugin's [`register` lifecycle](/cms/plugins-development/admin-panel-api#register). | 参数 | 类型 | 描述 || --- | --- | --- || `override` | 对象 | OpenAPI 对象,包括以下任意键:paths、tags、components。接受 JavaScript、JSON 或 YAML || `options` | 对象 | 接受 `pluginOrigin` 和 `excludeFromGeneration` || `options.pluginOrigin` | 字符串 | 注册覆盖的插件 || `options.excludeFromGeneration` | 字符串 或 字符串数组 | 要排除的 API/插件的名称,或名称列表 | :::caution 提供覆盖的插件开发者应始终指定 `pluginOrigin` 选项键。否则,无论用户的配置如何,覆盖都将运行。 🌐 Plugin developers providing an override should always specify the `pluginOrigin` options key. Otherwise the override will run regardless of the user’s configuration. ::: 文档插件将使用已注册的覆盖来替换生成文档中常用键的值,以覆盖提供的内容。如果未找到常用键,插件将向生成的文档中添加新键。 🌐 The Documentation plugin will use the registered overrides to replace the value of common keys on the generated documentation with what the override provides. If no common keys are found, the plugin will add new keys to the generated documentation. 如果覆盖完全替代了文档生成的内容,你可以通过在选项键数组 `excludeFromGeneration` 中提供要排除的 API 或插件名称,来指定不再需要生成。 🌐 If the override completely replaces what the documentation generates, you can specify that generation is no longer necessary by providing the names of the APIs or plugins to exclude in the options key array `excludeFromGeneration`. 如果覆盖仅应应用于特定版本,则覆盖必须包含 `info.version` 的值。否则,覆盖将对所有文档版本运行。 🌐 If the override should only be applied to a specific version, the override must include a value for `info.version`. Otherwise, the override will run on all documentation versions. ```js title="Application or plugin register lifecycle" module.exports = { register({ strapi }) { if (strapi.plugin('documentation')) { const override = { // Only run this override for version 1.0.0 info: { version: '1.0.0' }, paths: { '/answer-to-everything': { get: { responses: { 200: { description: "*" }} } } } } strapi .plugin('documentation') .service('override') .registerOverride(override, { // Specify the origin in case the user does not want this plugin documented pluginOrigin: 'upload', // The override provides everything don't generate anything excludeFromGeneration: ['upload'], }); } }, } ``` 覆盖系统旨在简化修改生成的文档。这是插件添加或修改生成文档的唯一方式。 🌐 The overrides system is provided to try and simplify amending the generated documentation. It is the only way a plugin can add or modify the generated documentation. ##### mutateDocumentation() {#mutate-documentation} 文档插件的配置也接受在 `info['x-strapi-config']` 上的 `mutateDocumentation` 函数。该函数接收生成文档的草稿状态,可以对其进行修改。它应仅从应用中应用,并在 OpenAPI 模式中拥有最终决定权。 🌐 The Documentation plugin’s configuration also accepts a `mutateDocumentation` function on `info['x-strapi-config']`. This function receives a draft state of the generated documentation that be can be mutated. It should only be applied from an application and has the final say in the OpenAPI schema. | 参数 | 类型 | 描述 || --- | --- | --- || `generatedDocumentationDraft` | 对象 | 应用覆盖后的生成文档,作为可变对象 | ```js title="config/plugins.js" module.exports = { documentation: { config: { "x-strapi-config": { mutateDocumentation: (generatedDocumentationDraft) => { generatedDocumentationDraft.paths[ "/answer-to-everything" // must be an existing path ].get.responses["200"].description = "*"; }, }, }, }, }; ``` ## 使用 {#usage} 🌐 Usage Documentation 插件使用 可视化你的 API。要访问 UI,请在管理面板的主导航中选择 。然后点击 **打开文档** 以打开 Swagger UI。使用 Swagger UI,你可以查看 API 上可用的所有端点并触发 API 调用。 :::tip 插件安装完成后,可以通过以下 URL 访问插件用户界面: `:/documentation/` (例如,)。 ::: ### 重新生成文档 {#regenerate-documentation} 🌐 Regenerating documentation 更改 API 后,有 2 种方法可以更新文档: 🌐 There are 2 ways to update the documentation after making changes to your API: - 重新启动你的应用以重新生成文档插件配置中指定的文档版本, - 或者转到文档插件页面,然后点击你想要重新生成的文档版本的**重新生成**按钮。 ### 认证请求 {#authenticating-requests} 🌐 Authenticating requests Strapi 默认是安全的,这意味着大多数端点都需要用户被授权。如果在 [用户与权限功能](/cms/features/users-permissions#roles) 中 CRUD 操作未设置为公开,那么你必须提供你的 JSON Web 令牌(JWT)。为此,在查看 API 文档时,点击 **授权** 按钮,并将你的 JWT 粘贴到 _bearerAuth_ _value_ 字段中。 🌐 Strapi is secured by default, which means that most of your endpoints require the user to be authorized. If the CRUD action has not been set to Public in the [Users & Permissions feature](/cms/features/users-permissions#roles) then you must provide your JSON web token (JWT). To do this, while viewing the API Documentation, click the **Authorize** button and paste your JWT in the _bearerAuth_ _value_ field. # GraphQL 插件 Source: https://docs.strapi.io/cms/plugins/graphql # GraphQL 插件 {#graphql-plugin} 🌐 GraphQL plugin 默认情况下,Strapi 会为你的每个内容类型创建 [REST 端点](/cms/api/rest#endpoints)。GraphQL 插件会添加一个 GraphQL 端点,以获取和修改你的内容。安装 GraphQL 插件后,你可以使用基于 Apollo Server 的 GraphQL 沙箱交互式地构建查询和变更,并查看针对你的内容类型定制的文档。 🌐 By default Strapi create [REST endpoints](/cms/api/rest#endpoints) for each of your content-types. The GraphQL plugin adds a GraphQL endpoint to fetch and mutate your content. With the GraphQL plugin installed, you can use the Apollo Server-based GraphQL Sandbox to interactively build your queries and mutations and read documentation tailored to your content types. 安装完成后,GraphQL 沙箱可以通过 `/graphql` URL 访问,并可用于交互式地构建你的查询和变更操作,以及阅读针对你的内容类型定制的文档。 🌐 Once installed, the GraphQL sandbox is accessible at the `/graphql` URL and can be used to interactively build your queries and mutations and read documentation tailored to your content-types. 一旦插件安装完成,当你的 Strapi 应用服务器运行时,**GraphQL Sandbox** 可以通过 `/graphql` 路由访问(例如, #### 动态启用 Apollo Sandbox {#dynamically-enable-apollo-sandbox} 🌐 Dynamically enable Apollo Sandbox 你可以使用一个函数根据环境动态启用 Apollo Sandbox: 🌐 You can use a function to dynamically enable Apollo Sandbox depending on the environment: #### 登录页面的 CORS 异常 {#cors-exceptions-for-landing-page} 🌐 CORS exceptions for Landing Page 如果在生产环境中启用了登录页面(不推荐),则必须手动添加 Apollo Server 登录页面的 CORS 标头。 🌐 If the landing page is enabled in production environments (which is not recommended), CORS headers for the Apollo Server landing page must be added manually. 要全局添加它们,你可以将以下内容合并到中间件配置中: 🌐 To add them globally, you can merge the following into your middleware configuration: ```javascript title="/config/middlewares" { name: "strapi::security", config: { contentSecurityPolicy: { useDefaults: true, directives: { "connect-src": ["'self'", "https:", "apollo-server-landing-page.cdn.apollographql.com"], "img-src": ["'self'", "data:", "blob:", "apollo-server-landing-page.cdn.apollographql.com"], "script-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"], "style-src": ["'self'", "'unsafe-inline'", "apollo-server-landing-page.cdn.apollographql.com"], "frame-src": ["sandbox.embed.apollographql.com"] } } } } ``` 要仅为 `/graphql` 路径添加这些例外(推荐),你可以创建一个新的中间件来处理它。例如: 🌐 To add these exceptions only for the `/graphql` path (recommended), you can create a new middleware to handle it. For example: #### 影子 CRUD {#shadow-crud} 🌐 Shadow CRUD 为了简化和自动化 GraphQL 架构的构建,我们引入了 Shadow CRUD 功能。它会根据你的模型自动生成类型定义、查询、变更和解析器。 🌐 To simplify and automate the build of the GraphQL schema, we introduced the Shadow CRUD feature. It automatically generates the type definitions, queries, mutations and resolvers based on your models. **示例:** 如果你使用 [交互式 `strapi generate` CLI](/cms/cli#strapi-generate) 或管理面板生成了一个名为 `Document` 的 API,你的模型看起来像这样: 🌐 If you've generated an API called `Document` using [the interactive `strapi generate` CLI](/cms/cli#strapi-generate) or the administration panel, your model looks like this: ```json title="/src/api/[api-name]/content-types/document/schema.json" { "kind": "collectionType", "collectionName": "documents", "info": { "singularName": "document", "pluralName": "documents", "displayName": "document", "name": "document" }, "options": { "draftAndPublish": true }, "pluginOptions": {}, "attributes": { "name": { "type": "string" }, "description": { "type": "richtext" }, "locked": { "type": "boolean" } } } ```
生成的 GraphQL 类型和查询 ```graphql # Document's Type definition input DocumentFiltersInput { name: StringFilterInput description: StringFilterInput locked: BooleanFilterInput createdAt: DateTimeFilterInput updatedAt: DateTimeFilterInput publishedAt: DateTimeFilterInput and: [DocumentFiltersInput] or: [DocumentFiltersInput] not: DocumentFiltersInput } input DocumentInput { name: String description: String locked: Boolean createdAt: DateTime updatedAt: DateTime publishedAt: DateTime } type Document { name: String description: String locked: Boolean createdAt: DateTime updatedAt: DateTime publishedAt: DateTime } type DocumentEntity { id: ID attributes: Document } type DocumentEntityResponse { data: DocumentEntity } type DocumentEntityResponseCollection { data: [DocumentEntity!]! meta: ResponseCollectionMeta! } type DocumentRelationResponseCollection { data: [DocumentEntity!]! } # Queries to retrieve one or multiple restaurants. type Query { document(id: ID): DocumentEntityResponse documents( filters: DocumentFiltersInput pagination: PaginationArg = {} sort: [String] = [] publicationState: PublicationState = LIVE ):DocumentEntityResponseCollection } # Mutations to create, update or delete a restaurant. type Mutation { createDocument(data: DocumentInput!): DocumentEntityResponse updateDocument(id: ID!, data: DocumentInput!): DocumentEntityResponse deleteDocument(id: ID!): DocumentEntityResponse } ```
#### 自定义 {#customization} 🌐 Customization Strapi 提供了一个编程 API 来自定义 GraphQL,它允许: 🌐 Strapi provides a programmatic API to customize GraphQL, which allows: * 为 [Shadow CRUD](#shadow-crud) 禁用某些操作 * [使用 getter](#using-getters) 来返回关于允许操作的信息 * 注册和使用一个 `extension` 对象来[扩展现有的模式](#extending-the-schema)(例如扩展类型或定义自定义解析器、策略和中间件)
GraphQL 自定义示例
##### 在 Shadow CRUD 中禁用操作 {#disabling-operations-in-the-shadow-crud} 🌐 Disabling operations in the Shadow CRUD `extension` 服务与 GraphQL 插件一起提供,公开的功能可以用于禁用内容类型的操作: 🌐 The `extension` service provided with the GraphQL plugin exposes functions that can be used to disable operations on Content-Types: | 内容类型功能 | 描述 | 参数类型 | 可能的参数值 || --- | --- | --- | --- || `disable()` | 完全禁用内容类型 | - | - || `disableQueries()` | 仅禁用内容类型的查询 | - | - || `disableMutations()` | 仅禁用内容类型的变更 | - | - || `disableAction()` | 禁用内容类型的特定操作 | 字符串 | 列表中的一个值:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
|| `disableActions()` | 禁用内容类型的特定操作 | 字符串数组 | 列表中的多个值:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| 还可以在字段级别禁用操作,具有以下功能: 🌐 Actions can also be disabled at the field level, with the following functions: | 字段功能 | 描述 || --- | --- || `disable()` | 完全禁用该字段 || `disableOutput()` | 禁用字段的输出 || `disableInput()` | 禁用字段的输入 || `disableFilters()` | 禁用字段的过滤输入 | **示例:** ```js // Disable the 'find' operation on the 'restaurant' content-type in the 'restaurant' API strapi .plugin('graphql') .service('extension') .shadowCRUD('api::restaurant.restaurant') .disableAction('find') // Disable the 'name' field on the 'document' content-type in the 'document' API strapi .plugin('graphql') .service('extension') .shadowCRUD('api::document.document') .field('name') .disable() ``` ##### 使用 getter 方法 {#using-getters} 🌐 Using getters 以下 getter 可用于检索有关内容类型上允许的操作的信息: 🌐 The following getters can be used to retrieve information about operations allowed on content-types: | 内容类型获取器 | 描述 | 参数类型 | 可能的参数值 | | --- | --- | --- | --- | | `isEnabled()` | 返回内容类型是否已启用 | - | - | | `isDisabled()` | 返回内容类型是否被禁用 | - | - | | `areQueriesEnabled()` | 返回内容类型上查询是否已启用 | - | - | | `areQueriesDisabled()` | 返回内容类型上的查询是否被禁用 | - | - | | `areMutationsEnabled()` | 返回内容类型上是否启用了变更 | - | - | | `areMutationsDisabled()` | 返回内容类型上的变更是否被禁用 | - | - | | `isActionEnabled(action)` | 返回指定 `action` 是否在内容类型上启用 | 字符串 | 列表中的一个值:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| | `isActionDisabled(action)` | 返回指定 `action` 在内容类型中是否被禁用 | 字符串 | 列表中的一个值:
  • `create`
  • `find`
  • `findOne`
  • `update`
  • `delete`
| 以下 getter 可用于检索有关字段上允许的操作的信息: 🌐 The following getters can be used to retrieve information about operations allowed on fields: | 字段获取器 | 描述 || --- | --- || `isEnabled()` | 返回字段是否启用 || `isDisabled()` | 返回字段是否禁用 || `hasInputEnabled()` | 返回字段是否启用输入 || `hasOutputEnabled()` | 返回字段是否启用输出 || `hasFiltersEnabled()` | 返回字段是否启用过滤 | ###### 扩展模式 {#extending-the-schema} 🌐 Extending the schema 可以通过注册扩展来扩展 Content API 生成的架构。 🌐 The schema generated by the Content API can be extended by registering an extension. 此扩展,可以定义为对象或返回对象的函数,将由由 GraphQL 插件提供的 `extension` [服务](/cms/backend-customization/services) 暴露的 `use()` 函数使用。 🌐 This extension, defined either as an object or a function returning an object, will be used by the `use()` function exposed by the `extension` [service](/cms/backend-customization/services) provided with the GraphQL plugin. 描述扩展的对象接受以下参数: 🌐 The object describing the extension accepts the following parameters: | 参数 | 类型 | 描述 || --- | --- | --- || `types` | 数组 | 允许使用基于
::: ###### 解析器的自定义配置 {#custom-configuration-for-resolvers} 🌐 Custom configuration for resolvers 解析器是 GraphQL 查询或变更处理器(即一个函数,或一组函数,用于为 GraphQL 查询或变更生成响应)。每个字段都有一个默认解析器。 🌐 A resolver is a GraphQL query or mutation handler (i.e. a function, or a collection of functions, that generate(s) a response for a GraphQL query or mutation). Each field has a default resolver. 当[扩展 GraphQL 架构](#extending-the-schema)时,`resolversConfig` 键可以用来为解析器定义自定义配置,其中可以包括: 🌐 When [extending the GraphQL schema](#extending-the-schema), the `resolversConfig` key can be used to define a custom configuration for a resolver, which can include: * [授权配置](#authorization-configuration) 使用 `auth` 密钥 * [带有 `policies` 键的策略](#policies) * 以及带有 `middlewares` 键的 [中间件](#middlewares) :::tip [高级查询](/cms/api/graphql/advanced-queries) 指南可能包含适用于你的使用场景的其他信息,包括多级查询和自定义解析器示例。 🌐 The [advanced queries](/cms/api/graphql/advanced-queries) guide might contain additional information suitable for your use case, including multi-level queries and custom resolvers examples. ::: ###### 授权配置 {#authorization-configuration} 🌐 Authorization configuration 默认情况下,GraphQL 请求的授权由已注册的授权策略处理,该策略可以是 [API 令牌](/cms/features/api-tokens) 或通过 [用户与权限插件](#usage-with-the-users--permissions-plugin)。用户与权限插件提供了更细粒度的控制。 🌐 By default, the authorization of a GraphQL request is handled by the registered authorization strategy that can be either [API token](/cms/features/api-tokens) or through the [Users & Permissions plugin](#usage-with-the-users--permissions-plugin). The Users & Permissions plugin offers a more granular control.
使用“用户与权限”插件进行授权 使用用户和权限插件,如果授予适当的权限,则允许 GraphQL 请求。 🌐 With the Users & Permissions plugin, a GraphQL request is allowed if the appropriate permissions are given. 例如,如果存在“类别”内容类型,并且通过 GraphQL 使用 `Query.categories` 处理器进行查询,则如果为“类别”内容类型授予了相应的 `find` 权限,请求将被允许。 🌐 For instance, if a 'Category' content-type exists and is queried through GraphQL with the `Query.categories` handler, the request is allowed if the appropriate `find` permission for the 'Categories' content-type is given. 要查询单个类别,可以使用 `Query.category` 处理程序,如果授予了 `findOne` 权限,则允许该请求。 🌐 To query a single category, which is done with the `Query.category` handler, the request is allowed if the the `findOne` permission is given. 请参阅用户指南,了解如何使用 [Users & Permissions 插件定义权限](/cms/features/rbac#editing-a-role)。
要更改授权的配置,请使用在 `resolversConfig.[MyResolverName]` 定义的解析器配置。授权可以配置为: 🌐 To change how the authorization is configured, use the resolver configuration defined at `resolversConfig.[MyResolverName]`. The authorization can be configured: * 或者使用 `auth: false` 完全绕过授权系统并允许所有请求, * 或者使用一个接受字符串数组的 `scope` 属性来定义授权请求所需的权限。
授权配置示例
###### 政策 {#policies} 🌐 Policies [策略](/cms/backend-customization/policies) 可以通过 `resolversConfig.[MyResolverName].policies` 键应用于 GraphQL 解析器。 `policies` 键是一个数组,接受策略列表,该列表中的每一项要么是对已注册策略的引用,要么是直接传入的实现(参见 [策略配置文档](/cms/backend-customization/routes#policies))。 🌐 The `policies` key is an array accepting a list of policies, each item in this list being either a reference to an already registered policy or an implementation that is passed directly (see [policies configuration documentation](/cms/backend-customization/routes#policies)). 在 `resolversConfig` 中直接实现的策略是函数,它们以 `context` 对象和 `strapi` 实例作为参数。 `context` 对象提供访问权限: 🌐 Policies directly implemented in `resolversConfig` are functions that take a `context` object and the `strapi` instance as arguments. The `context` object gives access to: * GraphQL 解析器的 `parent`、`args`、`context` 和 `info` 参数, * Koa 的 :::tip [高级策略](/cms/api/graphql/advanced-policies) 指南可能包含适合你使用场景的额外信息。 🌐 The [advanced policies](/cms/api/graphql/advanced-policies) guide might contain additional information suitable for your use case. ::: ###### 中间件 {#middlewares} 🌐 Middlewares [中间件](/cms/backend-customization/middlewares) 可以通过 `resolversConfig.[MyResolverName].middlewares` 键应用到 GraphQL 解析器。GraphQL 和 REST 实现之间的唯一区别是 `config` 键变成了 `options`。 `middlewares` 键是一个数组,接受中间件列表,该列表中的每一项要么是对已注册中间件的引用,要么是直接传入的实现(参见 [中间件配置文档](/cms/backend-customization/routes#middlewares))。 🌐 The `middlewares` key is an array accepting a list of middlewares, each item in this list being either a reference to an already registered middleware or an implementation that is passed directly (see [middlewares configuration documentation](/cms/backend-customization/routes#middlewares)). 直接在 `resolversConfig` 中实现的中间件可以将 GraphQL 解析器的 ##### 安全 {#security} 🌐 Security GraphQL 是一种查询语言,允许用户使用比传统 REST API 更广泛的输入。GraphQL API 本质上容易受到安全风险的影响,例如凭证泄露和拒绝服务攻击,但通过采取适当的预防措施可以减少这些风险。 🌐 GraphQL is a query language allowing users to use a broader panel of inputs than traditional REST APIs. GraphQL APIs are inherently prone to security risks, such as credential leakage and denial of service attacks, that can be reduced by taking appropriate precautions. ### 在生产环境中禁用自我检查和沙箱 {#disable-introspection-and-sandbox-in-production} 🌐 Disable introspection and Sandbox in production 在生产环境中,强烈建议禁用 GraphQL Sandbox 和 introspection 查询。如果你没有编辑[配置文件](#available-options),在生产环境中它默认已经被禁用。 🌐 In production environments, disabling the GraphQL Sandbox and the introspection query is strongly recommended. If you haven't edited the [configuration file](#available-options), it is already disabled in production by default. ###### 限制最大深度和复杂性 {#limit-max-depth-and-complexity} 🌐 Limit max depth and complexity 恶意用户可能会发送深度极高的查询,这可能会使你的服务器过载。使用 `depthLimit` [配置参数](/cms/plugins/graphql#code-based-configuration) 来限制单个请求中可查询的嵌套字段的最大数量。默认情况下,`depthLimit` 设置为 10,但在测试和开发期间可以设置为更高的值。 🌐 A malicious user could send a query with a very high depth, which could overload your server. Use the `depthLimit` [configuration parameter](/cms/plugins/graphql#code-based-configuration) to limit the maximum number of nested fields that can be queried in a single request. By default, `depthLimit` is set to 10 but can be set to a higher value during testing and development. :::tip 为了进一步提高 GraphQL 的安全性,可以使用第三方工具。请参阅关于 你应该在 Strapi 管理面板的 `Users` 集合类型中看到一个新用户已被创建。 🌐 You should see a new user is created in the `Users` collection type in your Strapi admin panel. #### 身份验证 {#authentication} 🌐 Authentication 要执行授权请求,你必须首先获取 JWT: 🌐 To perform authorized requests, you must first get a JWT: 然后在每个请求中,发送一个 `Authorization` 头,其形式为 `{ "Authorization": "Bearer YOUR_JWT_GOES_HERE" }`。这可以在你的 GraphQL Sandbox 的 HTTP 头部分设置。 🌐 Then on each request, send along an `Authorization` header in the form of `{ "Authorization": "Bearer YOUR_JWT_GOES_HERE" }`. This can be set in the HTTP Headers section of your GraphQL Sandbox. #### 使用 API 令牌 {#api-tokens} 🌐 Usage with API tokens 要使用 API 令牌进行身份验证,请使用格式 `Bearer your-api-token` 在 `Authorization` 头中传递令牌。 🌐 To use API tokens for authentication, pass the token in the `Authorization` header using the format `Bearer your-api-token`. :::note 在 GraphQL Sandbox 中使用 API 令牌需要在 `HTTP HEADERS` 选项卡中添加带有你的令牌的授权头: 🌐 Using API tokens in the the GraphQL Sandbox requires adding the authorization header with your token in the `HTTP HEADERS` tab: ```http { "Authorization" : "Bearer # 通过市场安装插件 Source: https://docs.strapi.io/cms/plugins/installing-plugins-via-marketplace # 使用市场 {#using-the-marketplace} 🌐 Using the Marketplace Strapi 自带了内置插件,例如 [Documentation](/cms/plugins/documentation)、[GraphQL](/cms/plugins/graphql) 和 [Sentry](/cms/plugins/sentry)。Marketplace 是用户可以找到额外插件以定制 Strapi 应用以及扩展插件的额外提供者的地方。Marketplace 位于管理面板中,用 _Marketplace_ 表示。在 Marketplace 中,用户可以浏览或搜索插件和提供者,链接到每个插件和提供者的详细描述,并提交新的插件和提供者。 :::note strapi In-app Marketplace vs. Market website 管理员面板中的市场显示所有现有插件,无论它们适用于哪个版本的 Strapi。所有插件也可以通过 网站进行发现。 但请记住,v4 和 v5 插件不相互兼容,但提供商与 v4 和 v5 插件都兼容。 🌐 Keep in mind however that v4 and v5 plugins are not cross-compatible, but that providers are compatible both with v4 and v5 plugins. ::: 插件和提供程序选项卡在各个卡上显示每个插件/提供程序,其中包含: 🌐 The Plugins and Providers tabs display each plugin/provider on individual cards containing: - 他们的名字,有时后面会跟以下任一徽章: - maintained by Strapi icon 表示它是由 Strapi 制作的, - 表示它已被 Strapi 验证。 - 该插件/提供者在 GitHub 上被加星和下载的次数 - 描述 - 一个 **更多** 按钮,可重定向到市场网站以获取更多信息,包括插件对应的 Strapi 版本以及实现说明 在市场的右上角,**提交插件**按钮会重定向到 Strapi 市场,在那里可以提交你自己的插件和提供者。 🌐 In the top right corner of the Marketplace, the **Submit plugin** button redirects to the Strapi Market where it is possible to submit your own plugin and provider. :::tip Tips - 搜索栏根据插件/提供者名称和描述显示增量搜索结果。 - 使用“排序方式”按钮或设置筛选条件以更轻松地找到插件。 ::: ## 安装Marketplace插件和提供程序 {#installing-marketplace-plugins-and-providers} 🌐 Installing Marketplace plugins and providers 要通过 Marketplace 安装新插件或提供程序: 🌐 To install a new plugin or provider via the Marketplace: 1. 前往 *市场*。 2. 选择 **插件** 选项卡以浏览可用插件,或选择 **提供商** 选项卡以浏览可用提供商。 3. 选择一个可用的插件/提供商,然后点击**更多** 按钮。 4. 重定向到 Strapi 市场网站后,请按照插件/提供商特定的实现说明进行操作。 :::strapi Developing Strapi plugins 找不到适合你使用场景的插件?随时可以[创建你自己的](/cms/plugins-development/developing-plugins)! 🌐 Can't find a plugin that suits your use case? Feel free to [create your own](/cms/plugins-development/developing-plugins)! ::: # Sentry 插件 Source: https://docs.strapi.io/cms/plugins/sentry # Sentry 插件 {#sentry-plugin} 🌐 Sentry plugin 此插件使你能够使用 Sentry 跟踪 Strapi 应用中的错误。 🌐 This plugin enables you to track errors in your Strapi application using Sentry. 通过使用 Sentry 插件,你可以: 🌐 By using the Sentry plugin you can: * 在 Strapi 应用启动时初始化 Sentry 实例 * 将 Strapi 应用错误作为事件发送到 Sentry * 在 Sentry 事件中包含其他元数据以协助调试 * 公开 Strapi 服务器可用的全局 Sentry 服务 ## 安装 {#installation} 🌐 Installation 通过将依赖添加到 Strapi 应用来安装 Sentry 插件,如下所示: 🌐 Install the Sentry plugin by adding the dependency to your Strapi application as follows: ## 配置 {#configuration} 🌐 Configuration 创建或编辑你的 `/config/plugins` 文件以配置 Sentry 插件。以下属性可用: 🌐 Create or edit your `/config/plugins` file to configure the Sentry plugin. The following properties are available: | 属性 | 类型 | 默认值 | 描述 || --- | --- | --- |--- || `dsn` | 字符串 | `null` | 你的 Sentry ### 为非生产环境禁用 {#disabling-for-non-production-environments} 🌐 Disabling for non-production environments 如果在 `sentry.enabled` 为 true 的情况下将 `dsn` 属性设置为 nil 值(`null` 或 `undefined`),Sentry 插件将在正在运行的 Strapi 实例中可用,但该服务实际上不会将错误发送到 Sentry。这样可以让你编写在每个环境中都能运行的代码,而无需额外检查,但只在生产环境中将错误发送到 Sentry。 🌐 If the `dsn` property is set to a nil value (`null` or `undefined`) while `sentry.enabled` is true, the Sentry plugin will be available to use in the running Strapi instance, but the service will not actually send errors to Sentry. That allows you to write code that runs on every environment without additional checks, but only send errors to Sentry in production. 当你使用值为 nil 的 `dsn` 配置属性启动 Strapi 时,该插件将打印以下警告:
`info: @strapi/plugin-sentry is disabled because no Sentry DSN was provided` 🌐 When you start Strapi with a nil `dsn` config property, the plugin will print the following warning:
`info: @strapi/plugin-sentry is disabled because no Sentry DSN was provided` 你可以通过使用[`env` 工具](/cms/configurations/guides/access-cast-environment-variables)来根据环境设置 `dsn` 配置属性,从而利用这一点。 🌐 You can make use of that by using the [`env` utility](/cms/configurations/guides/access-cast-environment-variables) to set the `dsn` configuration property depending on the environment. ### 完全禁用插件 {#disabling-the-plugin-completely} 🌐 Disabling the plugin completely 像其他所有 Strapi 插件一样,你也可以在插件配置文件中禁用此插件。这将导致 `strapi.plugins('sentry')` 返回 `undefined`: 🌐 Like every other Strapi plugin, you can also disable this plugin in the plugins configuration file. This will cause `strapi.plugins('sentry')` to return `undefined`: ## 使用 {#usage} 🌐 Usage 安装并配置插件后,你可以在 Strapi 应用中访问 Sentry 服务,如下所示: 🌐 After installing and configuring the plugin, you can access a Sentry service in your Strapi application as follows: ```js const sentryService = strapi.plugin('sentry').service('sentry'); ``` 该服务公开了以下方法: 🌐 This service exposes the following methods: | 方法 | 描述 | 参数 || --- | --- | --- || `sendError()` | 手动将错误发送到 Sentry。 |
  • error:要发送的错误。
  • configureScope:可选。允许你自定义错误事件。
详情请参见官方 。 || `getInstance()` | 用于直接访问 Sentry 实例。 | - | `sendError()` 方法可以如下使用: 🌐 The `sendError()` method can be used as follows: ```js try { // Your code here } catch (error) { // Either send a simple error strapi .plugin('sentry') .service('sentry') .sendError(error); // Or send an error with a customized Sentry scope strapi .plugin('sentry') .service('sentry') .sendError(error, (scope, sentryInstance) => { // Customize the scope here scope.setTag('my_custom_tag', 'Tag value'); }); throw error; } ``` `getInstance()` 方法可通过以下方式访问: 🌐 The `getInstance()` method is accessible as follows: ```js const sentryInstance = strapi .plugin('sentry') .service('sentry') .getInstance(); ``` # 项目结构 Source: https://docs.strapi.io/cms/project-structure # 项目结构 {#project-structure} 🌐 Project structure Strapi 项目的结构取决于项目是使用 [TypeScript](/cms/typescript)(如果你在创建项目时使用了 `--quickstart` 选项,这将是默认选项)还是使用普通 JavaScript 创建的,其结构如下所示: 🌐 The structure of a Strapi project depends on whether the project was created with [TypeScript](/cms/typescript) (which is the default if you used the `--quickstart` option while creating the project) or with vanilla JavaScript, and looks like the following: # 快速入门指南 - Strapi 开发者文档 Source: https://docs.strapi.io/cms/quick-start # 快速入门指南 {#quick-start-guide} 🌐 Quick Start Guide Strapi 提供了很大的灵活性。无论你是想快速行动并迅速看到最终结果,还是更愿意深入研究产品,我们都能满足你的需求。在本教程中,我们将采用 DIY 方法,从零开始构建一个项目和内容结构,然后将你的项目部署到 Strapi Cloud,从那里添加数据。 🌐 Strapi offers a lot of flexibility. Whether you want to go fast and quickly see the final result, or would rather dive deeper into the product, we got you covered. For this tutorial, we'll go for the DIY approach and build a project and content structure from scratch, then deploy your project to Strapi Cloud to add data from there. :::strapi 3 options to discover Strapi 有三种方式可以了解 Strapi。选择最适合你的方式: 🌐 There are 3 options to discover Strapi. Choose what best suits you: * Strapi 提供了一个[托管演示](https://strapi.io/demo),让你可以快速体验其内容管理器并学习如何编辑内容。在此托管演示中,Strapi 以生产模式运行,因此内容类型构建器根据设计是[禁用的](/cms/faq#why-cant-i-create-or-update-content-types-in-productionstaging)。 * 如果你想尝试一个完整的应用,包括 Strapi 后端、Next.js 前端和示例数据,请在本地安装 [LaunchPad](https://github.com/strapi/launchpad) 应用。 * 如果你想学习如何从零开始,请遵循本快速入门指南。 ::: :::prerequisites 2. 终端会提示你登录或注册。一旦完成,你的项目将自动获得 3. 在终端中回答问题,为你的项目命名(你可以按 Enter 保留默认名称),选择推荐的 NodeJS 版本,并选择更接近你当前位置的区域: s th![Strapi Cloud 终端问答](/img/assets/quick-start-guide/qsg-strapi-cloud-terminal-questions.png) 几分钟内,你的本地项目将托管在 Strapi 云上。🚀 🌐 Within a few moments, your local project will be hosted on Strapi Cloud. 🚀 一旦完成,终端将提供一个以 `https://cloud.strapi.io/projects` 开头的可点击链接。点击该链接,或将其复制并粘贴到浏览器地址栏中,以访问该页面。 🌐 Once it's done, the terminal will provide you a clickable link that starts with `https://cloud.strapi.io/projects`. Click on the link, or copy and paste it in your browser address bar, to visit the page. 你将在 Strapi Cloud 仪表板中看到我们刚创建的 Strapi Cloud 项目 `my-strapi-project`。点击右上角的 **访问应用** 按钮以访问你已部署的 Strapi 项目。 🌐 You will see the Strapi Cloud project we've just created, `my-strapi-project`, visible in the Strapi Cloud dashboard. Click the **Visit app** button in the top right corner to access your deployed Strapi project. :::callout Congratulations! 现在你的项目已托管在 Strapi Cloud 上并可在线访问。你可以通过阅读 [其专用文档](/cloud/intro) 来了解有关 Strapi Cloud 的更多信息,或者继续到 D 部分登录你的在线 Strapi 项目并从那里添加你的第一个数据。 🌐 Now your project is hosted on Strapi Cloud and accessible online. You can learn more about Strapi Cloud by reading [its dedicated documentation](/cloud/intro) or proceed to part D to log in into your online Strapi project and add your first data from there. ::: :::tip 尽管随意进一步使用内容类型构建器,为你的内容类型添加更多字段或创建新的内容类型。每当你进行此类更改时,通过运行适当的 `deploy` 命令再次将其部署到 Strapi Cloud,并在几分钟内看到你的托管项目更新。神奇,不是吗?🪄 🌐 Feel free to play with the Content-Type Builder even further and add more fields to your content-types or create new content-types. Anytime you make such changes, deploy them again on Strapi Cloud, by running the appropriate `deploy` command, and see your hosted project updated within a few minutes. Magical, isn't it? 🪄 ::: ## 第 D 部分:使用内容管理器向你的 Strapi Cloud 项目添加内容 {#icon-namenote-pencil--part-d-add-content-to-your-strapi-cloud-project-with-the-content-manager} 现在我们已经创建了一个包含两个集合类型“Restaurant”和“Category”的基本内容结构,并将你的项目部署到了 Strapi Cloud,我们来使用 Cloud 实际添加内容,通过创建新的条目。 🌐 Now that we have created a basic content structure with 2 collection types, "Restaurant" and "Category", and deployed your project to Strapi Cloud, let's use the Cloud to actually add content by creating new entries.
步骤 1:登录到你新的 Strapi Cloud 项目的管理面板 ### 步骤 1:登录到你新的 Strapi Cloud 项目的管理面板 {#step-1-log-in-to-the-admin-panel-of-your-new-strapi-cloud-project} 🌐 Step 1: Log in to the admin panel of your new Strapi Cloud project 现在你的 Strapi Cloud 项目已创建,让我们登录该项目: 🌐 Now that your Strapi Cloud project is created, let's log in into the project: 1. 在你的 中,点击 `my-strapi-project` 项目。 3. 点击 **访问应用** 按钮。 4. 在打开的新页面中,填写表单以创建此 Strapi Cloud 项目的第一个管理员用户。 登录到我们的第一个 Strapi Cloud 项目,我们现在将从那里添加数据。 🌐 Logged in into our first Strapi Cloud project, we will now add data from there.
关于用户和 Strapi Cloud 项目的附加信息和提示: :::note Note: Local users and Strapi Cloud users are different 你的 Strapi Cloud 项目和本地项目的数据库是不同的。这意味着数据不会自动从本地项目传输到 Strapi Cloud。这包括你之前在本地创建的用户。这就是为什么当你第一次登录到 Strapi Cloud 项目时,会被邀请创建一个新的管理员账户的原因。 🌐 The databases for your Strapi Cloud project and your local project are different. This means that data is not automatically transferred from your local project to Strapi Cloud. This includes users that you previously created locally. That's why you are invited to create a new administrator account when logging in to your Strapi Cloud project for the first time. ::: :::tip Tip: Directly accessing the admin panel of your Strapi Cloud project 任何托管在 Strapi Cloud 上的项目都可以通过其自己的网址访问,例如 `https://my-strapi-project-name.strapiapp.com`。要访问你的在线项目的管理面板,只需在网址后添加 `/admin`,例如 `https://my-strapi-project-name.strapiapp.com/admin`。网址可以在你的 Strapi Cloud 仪表板中找到,你也可以直接从那里访问你的 Strapi Cloud 项目,方法是点击项目名称,然后点击 **访问应用** 按钮。 🌐 Any project hosted on Strapi Cloud is accessible from its own URL, something like `https://my-strapi-project-name.strapiapp.com`. To access the admin panel of your online project, simply add `/admin` to the URL, for instance as in `https://my-strapi-project-name.strapiapp.com/admin`. URLs can be found in your Strapi Cloud dashboard and you can also directly access your Strapi Cloud projects from there by clicking on the name of your project then on the **Visit app** button. :::
第2步:为“餐厅”集合类型创建一个条目 ### 步骤 2:为“餐厅”集合类型创建一个条目 {#step-2-create-an-entry-for-the-restaurant-collection-type} 🌐 Step 2: Create an entry for the "Restaurant" collection type 1. 在导航中转到 _内容管理器 > 集合类型 - 餐厅_。 2. 点击 **创建新条目**。 3. 在 _Name_ 字段中输入你最喜欢的本地餐厅的名字。假设是 `Biscotte Restaurant`。 4. 在_描述_字段中,写几句话。如果你缺乏一些灵感,你可以使用`Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers.` 5. 点击 **保存**。 该餐厅现在已列在 _内容管理器_的_合集类型 - 餐厅_视图中。
步骤 3:添加类别 #### 步骤 3:添加类别 {#step-3-add-categories} 🌐 Step 3: Add Categories 让我们去 _内容管理器 > 集合类型 - 分类_ 并创建两个分类: 1. 点击 **创建新条目**。 2. 在 _名称_ 字段中输入 `French Food`。 3. 点击 **保存**。 4. 返回到 _Collection types - Category_,然后再次点击 **Create new entry**。 5. 在 _Name_ 字段中输入 `Brunch`,然后点击 **保存**。 “French Food”和“Brunch”类别现在在 _内容管理器_的_集合类型 - 类别_视图中列为草稿。 现在,我们将为餐厅添加一个类别: 🌐 Now, we will add a category to a restaurant: 1. 在导航中转到 _内容管理器 > 集合类型 - 餐厅_,然后点击“Biscotte 餐厅”。 2. 在页面底部的 **类别** 下拉列表中,选择“法国美食”。然后滚动回页面顶部,点击 **保存**。
步骤 4:设置角色和权限 ### 步骤 4:设置角色和权限 {#step-4-set-roles--permissions} 🌐 Step 4: Set Roles & Permissions 我们刚刚添加了一家餐厅和两个类别。我们现在有足够的内容可以使用(双关语意在食用)。但首先,我们需要确保这些内容可以通过 API 公开访问: 🌐 We have just added a restaurant and 2 categories. We now have enough content to consume (pun intended). But first, we need to make sure that the content is publicly accessible through the API: 1. 点击主导航底部的 _ 设置_。 2. 在 _用户与权限插件_ 下,选择 _角色_。 3. 点击 **公开** 角色。 4. 在_权限_下向下滚动。 5. 在“权限”选项卡中,找到“餐厅”并点击它。 6. 点击 **find** 和 **findOne** 旁边的复选框。 7. 在 _Category_ 中重复:点击 **find** 和 **findOne** 旁边的复选框。 8. 最后,点击页面顶部的 **保存**。
第5步:发布内容 ### 步骤 5:发布内容 {#step-5-publish-the-content} 🌐 Step 5: Publish the content 默认情况下,你创建的任何内容都会被保存为草稿。让我们发布我们的分类和餐厅。 🌐 By default, any content you create is saved as a draft. Let's publish our categories and restaurant. 首先,导航到 _内容管理器 > 集合类型 - 分类_。从那里: 1. 点击“早午餐”条目。 2. 在下一个屏幕上,点击 **发布**。 然后,回到类别列表,重复操作“法国食品”类别。 🌐 Then, go back to the Categories list and repeat for the "French Food" category. 最后,要发布你最喜欢的餐厅,请前往 _内容管理器 > 集合类型 - 餐厅_,点击“Biscotte 餐厅”条目,然后**发布**它。
第6步:使用API ### 步骤 6:使用API {#step-6-use-the-api} 🌐 Step 6: Use the API 好的,亲爱的美食家,我们刚刚完成了内容的创建,并通过 API 使其可访问。你可以为自己鼓掌——但你还没有看到你辛勤工作的最终成果。 🌐 OK dear gourmet, we have just finished creating our content and making it accessible through the API. You can give yourself a pat on the back — but you have yet to see the final result of your hard work. 就在这里:餐厅列表可以通过访问你的 Strapi Cloud 项目 URL 的 `/api/restaurants` 路径来访问(例如,`https://beautiful-first-strapi-project.strapiapp.com/api/restaurants`)。 🌐 There you are: the list of restaurants should be accessible by visting the `/api/restaurants` path of your Strapi Cloud project URL (e.g., `https://beautiful-first-strapi-project.strapiapp.com/api/restaurants`). 现在就试试吧!结果应该类似于下面的示例回应 👇。 🌐 Try it now! The result should be similar to the example response below 👇.
点击我查看 API 响应示例: ```json { "data": [ { "id": 3, "documentId": "wf7m1n3g8g22yr5k50hsryhk", "Name": "Biscotte Restaurant", "Description": [ { "type": "paragraph", "children": [ { "type": "text", "text": "Welcome to Biscotte restaurant! Restaurant Biscotte offers a cuisine based on fresh, quality products, often local, organic when possible, and always produced by passionate producers." } ] } ], "createdAt": "2024-09-10T12:49:32.350Z", "updatedAt": "2024-09-10T13:14:18.275Z", "publishedAt": "2024-09-10T13:14:18.280Z", "locale": null } ], "meta": { "pagination": { "page": 1, "pageSize": 25, "pageCount": 1, "total": 1 } } } ```
:::callout Congratulations! 现在你的内容已经创建并发布,并且你有权限通过 API 请求它。继续创作精彩的内容吧! 🌐 Now your content is created, published, and you have permissions to request it through the API. Keep on creating amazing content! ::: :::tip Tip: Transfer data between your local and Strapi Cloud projects 你的 Strapi Cloud 项目和本地项目的数据库是不同的。这意味着数据不会在你的 Strapi Cloud 和本地项目之间自动同步。你可以使用 [数据管理系统](/cms/features/data-management) 在项目之间传输数据。 🌐 The databases for your Strapi Cloud project and your local project are different. This means that data is not automatically synchronized between your Strapi Cloud and local projects. You can use the [data management system](/cms/features/data-management) to transfer data between projects. ::: ## 接下来做什么? {#icon-namefast-forward-what-to-do-next} 现在你已经了解了使用 Strapi 创建和发布内容的基础知识,我们鼓励你更深入地探索和挖掘 Strapi 的一些功能: 🌐 Now that you know the basics of creating and publishing content with Strapi, we encourage you to explore and dig deeper into some Strapi features: 学习如何使用 Strapi 的 [REST](/cms/api/rest) API 查询内容,
通过浏览 **功能** 类别了解更多 Strapi 功能,
通过阅读 [云文档](/cloud/intro) 了解更多 Strapi Cloud 项目,
并为高级用例 [自定义你的 Strapi 后端](/cms/backend-customization) 和 [管理面板](/cms/admin-panel-customization)。
# 模板 Source: https://docs.strapi.io/cms/templates # 模板 {#templates} 🌐 Templates Strapi 5 中的模板是独立的、预制的 Strapi 应用,专为特定用例而设计。 🌐 Templates in Strapi 5 are standalone, pre-made Strapi applications designed for specific use cases. Strapi 5 模板是包含典型 Strapi 应用中所有文件和文件夹的文件夹(参见 [项目结构](/cms/project-structure))。 🌐 Strapi 5 templates are folders that include all files and folders that you would find in a typical Strapi application (see [project structure](/cms/project-structure)). ## 使用模板 {#using-a-template} 🌐 Using a template 要基于模板创建新的 Strapi 项目,请运行以下命令: 🌐 To create a new Strapi project based on a template, run the following command: 除了必需的 `--template` 参数外,你还可以传递可选的 `--template-path` 和 `--template-branch` 选项来更精确地定义要使用的模板。 🌐 In addition to the mandatory `--template` parameter, you can pass the optional `--template-path` and `--template-branch` options to more precisely define the template to use. 下表列出了定义要使用哪个模板的所有可能方法: 🌐 The following table lists all the possible ways to define which template to use: | 语法 | 描述 | |--------|-------------| | `--template website` | 使用其中一个 通过其(文件夹)名称来调用它。 | | `--template strapi/strapi` | 使用模板的 GitHub 仓库简写。
这将使用默认的仓库分支。 | | `--template strapi/strapi/some/sub/path` | 使用模板的 GitHub 仓库简写并指定子路径。
这将使用默认的仓库分支。 | | `--template strapi/strapi`
`--template-branch=xxx`
`--template-path=some/sub/path` | 最冗长的方式,明确地定义一个模板分支和一个子路径。 | | `--template https://github.com/owner/some-template-repo` | 使用完整的仓库 URL。
这将使用默认的仓库分支。 | | `--template https://github.com/owner/some-template-repo --template-branch=xxx --template-path=sub/path` | 使用完整的仓库 URL,并同时指定模板的分支和子路径。 | | `--template https://github.com/strapi/strapi/tree/branch/sub/path` | 直接使用仓库、分支和子路径。

⚠️ _警告:如果分支名称中包含 `/`,这将无法使用。在这种情况下,最好显式定义 `--template-branch` 和 `--template-path`。_ | ## 创建模板 {#creating-a-template} 🌐 Creating a template 创建一个 Strapi 5 模板和创建一个 Strapi 应用一样简单。创建应用(参见 [CLI 安装](/cms/installation/cli)),生成的包含你的 Strapi 5 应用的文件夹可以作为模板。然后,在创建新的 Strapi 5 应用时,可以将其传递给 `--template` 标志以将其用作模板。 🌐 Creating a Strapi 5 template is as simple as creating a Strapi application. Create the application (see [CLI installation](/cms/installation/cli)) and the generated folder containing your Strapi 5 application can serve as a template. You can then pass it to the `--template` flag when creating a new Strapi 5 application to use it as a template. 模板可能的示例是由 Strapi 维护的 。 🌐 An example of what a template could look like is the . # 测试 Source: https://docs.strapi.io/cms/testing # 单元和集成测试指南 {#unit-and-integration-testing-guide} 🌐 Unit and integration testing guide 本指南提供了一种动手的方法,用于在 Strapi 5 应用中配置 * `Jest` 提供测试运行器和断言工具。 * `Supertest` 允许你测试所有作为 ` 工具来重现 Strapi 对象的部分以及你的代码依赖的任何请求上下文。 ### 控制器示例 {#controller-example} 🌐 Controller example 创建一个测试文件,例如 `./tests/todo-controller.test.js`,该文件使用模拟的 Strapi 对象实例化你的控制器,并验证控制器执行的每一个调用: 🌐 Create a test file such as `./tests/todo-controller.test.js` that instantiates your controller with a mocked Strapi object and verifies every call the controller performs: ```js title="./tests/todo-controller.test.js" const todoController = require('./todo-controller'); describe('Todo controller', () => { let strapi; beforeEach(() => { strapi = { plugin: jest.fn().mockReturnValue({ service: jest.fn().mockReturnValue({ create: jest.fn().mockReturnValue({ data: { name: 'test', status: false, }, }), complete: jest.fn().mockReturnValue({ data: { id: 1, status: true, }, }), }), }), }; }); it('creates a todo item', async () => { const ctx = { request: { body: { name: 'test', }, }, body: null, }; await todoController({ strapi }).index(ctx); expect(ctx.body).toBe('created'); expect(strapi.plugin('todo').service('create').create).toHaveBeenCalledTimes(1); }); it('completes a todo item', async () => { const ctx = { request: { body: { id: 1, }, }, body: null, }; await todoController({ strapi }).complete(ctx); expect(ctx.body).toBe('todo completed'); expect(strapi.plugin('todo').service('complete').complete).toHaveBeenCalledTimes(1); }); }); ``` `beforeEach` 钩子重建了 mock,因此每个测试都从一个干净的 Strapi 实例开始。每个测试会准备控制器所期望的 `ctx` 请求对象,调用控制器函数,并断言响应以及与 Strapi 服务的交互。 🌐 The `beforeEach` hook rebuilds the mock so every test starts with a clean Strapi instance. Each test prepares the `ctx` request object that the controller expects, calls the controller function, and asserts both the response and the interactions with Strapi services. ### 服务示例 {#service-example} 🌐 Service example 服务可以在同一个测试套件中进行测试,也可以在专用文件中通过仅模拟它们调用的 Strapi 查询层进行测试。 🌐 Services can be tested in the same test suite or in a dedicated file by mocking only the Strapi query layer they call into. ```js title="./tests/create-service.test.js" const createService = require('./create-service'); describe('Create service', () => { let strapi; beforeEach(() => { strapi = { query: jest.fn().mockReturnValue({ create: jest.fn().mockReturnValue({ data: { name: 'test', status: false, }, }), }), }; }); it('persists a todo item', async () => { const todo = await createService({ strapi }).create({ name: 'test' }); expect(strapi.query('plugin::todo.todo').create).toHaveBeenCalledTimes(1); expect(todo.data.name).toBe('test'); }); }); ``` 通过专注于 mocking 代码接触到的特定 Strapi API,你可以扩展这些测试以覆盖更多分支、错误情况和服务,同时保持它们的快速和隔离。 🌐 By focusing on mocking the specific Strapi APIs your code touches, you can grow these tests to cover additional branches, error cases, and services while keeping them fast and isolated. ## 建立测试环境 {#set-up-a-testing-environment} 🌐 Set up a testing environment 对于使用 用于为测试设置和拆除 Strapi 实例 ### TypeScript 编译器配置 {#typescript-compiler-configuration} 🌐 TypeScript compiler configuration 使用以下内容创建 `tests/ts-compiler-options.js`: 🌐 Create `tests/ts-compiler-options.js` with the following content: ```js title="./tests/ts-compiler-options.js" const fs = require('fs'); const path = require('path'); const ts = require('typescript'); const projectRoot = path.resolve(__dirname, '..'); const tsconfigPath = path.join(projectRoot, 'tsconfig.json'); const baseCompilerOptions = { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2019, moduleResolution: ts.ModuleResolutionKind.NodeJs, esModuleInterop: true, jsx: ts.JsxEmit.React, }; const loadCompilerOptions = () => { let options = { ...baseCompilerOptions }; if (!fs.existsSync(tsconfigPath)) { return options; } try { const tsconfigContent = fs.readFileSync(tsconfigPath, 'utf8'); const parsed = ts.parseConfigFileTextToJson(tsconfigPath, tsconfigContent); if (!parsed.error && parsed.config && parsed.config.compilerOptions) { options = { ...options, ...parsed.config.compilerOptions, }; } } catch (error) { // Ignore tsconfig parsing errors and fallback to defaults } return options; }; module.exports = { compilerOptions: loadCompilerOptions(), loadCompilerOptions, }; ``` 此文件加载项目的 TypeScript 配置,并在配置文件不存在时提供合理的默认值。 🌐 This file loads your project's TypeScript configuration and provides sensible defaults if the config file doesn't exist. ### TypeScript 运行时加载器 {#typescript-runtime-loader} 🌐 TypeScript runtime loader 使用以下内容创建 `tests/ts-runtime.js`: 🌐 Create `tests/ts-runtime.js` with the following content: ```js title="./tests/ts-runtime.js" const Module = require('module'); const { compilerOptions } = require('./ts-compiler-options'); const fs = require('fs'); const ts = require('typescript'); const extensions = Module._extensions; if (!extensions['.ts']) { extensions['.ts'] = function compileTS(module, filename) { const source = fs.readFileSync(filename, 'utf8'); const output = ts.transpileModule(source, { compilerOptions, fileName: filename, reportDiagnostics: false, }); return module._compile(output.outputText, filename); }; } if (!extensions['.tsx']) { extensions['.tsx'] = extensions['.ts']; } module.exports = { compilerOptions, }; ``` 这个文件教 Node.js 如何通过即时将 `.ts` 和 `.tsx` 文件转译为 JavaScript 来加载它们。 🌐 This file teaches Node.js how to load `.ts` and `.tsx` files by transpiling them to JavaScript on the fly. ### 主测试框架 {#main-test-harness} 🌐 Main test harness 使用以下内容创建 `tests/strapi.js`: 🌐 Create `tests/strapi.js` with the following content: 测试工具的作用: 🌐 What the test harness does: 1. **TypeScript 支持**:修补 Strapi 的配置加载器,以便在你的配置目录中识别 TypeScript 文件(`.ts`、`.cts`、`.mts`) 2. **配置验证**:确保只加载有效的配置文件,并对常见错误发出警告(例如将文件命名为 `middleware.js` 而不是 `middlewares.js`) 3. **数据库规范化**:将数据库客户端名称映射到其实际驱动程序名称(例如,`sqlite` → `sqlite3`)并处理连接池 4. **环境设置**:设置测试所需的所有环境变量,包括 JWT 秘钥和数据库配置 5. **自动路由注册**:自动注册一个 `/api/hello` 测试端点,你可以在测试中使用 6. **用户权限助手**:修补用户服务,以自动将“已认证”角色分配给新创建的用户,从而简化身份验证测试 7. **清理**:在测试完成后,正确关闭连接并删除临时数据库文件 :::note `tests/strapi.js` 测试框架的代码示例高亮了第 313-321 行,因为这些是可选的,如果你 [种子可预测的测试数据](#optional-seed-predictable-test-data) 则使用它们。 🌐 The code example for the `tests/strapi.js` harness highlights lines 313-321 because these are optional, to be used if you [seed predictable test data](#optional-seed-predictable-test-data). ::: 这些文件到位后,线束会自动处理 Strapi 5 的多项需求,让你专注于编写实际测试逻辑,而不是配置样板。 🌐 Once these files are in place, the harness handles several Strapi 5 requirements automatically, letting you focus on writing actual test logic rather than configuration boilerplate. ## (可选) 生成可预测的测试数据 {#optional-seed-predictable-test-data} 🌐 (optional) Seed predictable test data 一些 API 测试在预先加载已知文档集时会受益。你可以将项目的初始化数据功能作为可重用的函数暴露出来,并在环境标志下从测试框架中调用它: 🌐 Some API tests benefit from having a known set of documents preloaded. You can expose your project seeding as a reusable function and call it from the harness behind an environment flag: 1. 从你的项目脚本中导出一个播种函数(例如 `./scripts/seed.js`): ```js title="./scripts/seed.js" async function seedExampleApp() { // In test environment, skip complex seeding and just log if (process.env.NODE_ENV === 'test') { console.log('Test seeding: Skipping complex data import (not needed for basic tests)'); return; } const shouldImportSeedData = await isFirstRun(); if (shouldImportSeedData) { try { console.log('Setting up the template...'); await importSeedData(); console.log('Ready to go'); } catch (error) { console.log('Could not import seed data'); console.error(error); } } } // Allow usage both as a CLI and as a library from tests if (require.main === module) { main().catch((error) => { console.error(error); process.exit(1); }); } module.exports = { seedExampleApp }; ``` 2. 在测试框架中,当 `TEST_SEED=true` 时调用该函数(参见 [主测试框架](#main-test-harness) 的代码示例中高亮的第 313-321 行)。 3. 启用种子功能运行测试: 种子功能在 Strapi 启动后运行,因此服务、权限和上传功能均可用。 🌐 Seeding runs after Strapi starts, so services, permissions, and uploads are available. 建议保持种子确定性以确保断言稳定。如果发布条目,最好使用固定时间戳或对结构属性进行断言,而不是对瞬时日期进行断言。 🌐 It's recommended to keep seeds deterministic to ensure stable assertions. If you publish entries, prefer fixed timestamps or assert on structural properties rather than transient dates. ## 创建冒烟测试 {#create-smoke-tests} 🌐 Create smoke tests 在安装好测试环境后,你可以通过添加一个最小的 Jest 测试套件来确认 Strapi 是否正确启动,包含以下**冒烟测试** 在 `tests/app.test.js` 中如下所示: ```js title="./tests/app.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); /** this code is called once before any test is called */ beforeAll(async () => { await setupStrapi(); // Singleton so it can be called many times }); /** this code is called once before all the tests are finished */ afterAll(async () => { await cleanupStrapi(); }); it('strapi is defined', () => { expect(strapi).toBeDefined(); }); require('./hello'); require('./user'); ``` 运行 `yarn test` 或 `npm run test` 现在应该会得到: 🌐 Running `yarn test` or `npm run test` should now yield: ```bash PASS tests/create-service.test.js PASS tests/todo-controller.test.js Test Suites: 6 passed, 6 total Tests: 7 passed, 7 total Snapshots: 0 total Time: 7.952 s Ran all test suites. ✨ Done in 8.63s. ``` :::caution 如果你在使用 Jest 时收到超时错误,可以通过在 `tests/strapi.js` 中或测试文件顶部调用 `jest.setTimeout(30000)` 来增加超时时间。 🌐 If you receive a timeout error for Jest, increase the timeout by calling `jest.setTimeout(30000)` in `tests/strapi.js` or at the top of your test file. ::: ## 测试一个基本的 API 端点 {#test-a-basic-api-endpoint} 🌐 Test a basic API endpoint 使用以下内容创建 `tests/hello.test.js`: 🌐 Create `tests/hello.test.js` with the following: ```js title="./tests/hello.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); it('should return hello world', async () => { await request(strapi.server.httpServer) .get('/api/hello') .expect(200) .then((data) => { expect(data.text).toBe('Hello World!'); }); }); ``` 该框架会自动注册 `/api/hello` 路由,因此测试只需发出请求即可。 🌐 The harness registers the `/api/hello` route automatically, so the test only has to make the request. ## 测试 API 身份验证 {#test-api-authentication} 🌐 Test API authentication Strapi 使用 JWT 令牌来处理身份验证。我们将创建一个具有已知用户名和密码的用户,并使用这些凭据进行身份验证以获取 JWT 令牌。测试工具中的修补 `user.add` 辅助函数确保已自动应用经过身份验证的角色。 🌐 Strapi uses a JWT token to handle authentication. We will create one user with a known username and password, and use these credentials to authenticate and get a JWT token. The patched `user.add` helper in the harness ensures the authenticated role is applied automatically. 创建 `tests/auth.test.js`: 🌐 Create `tests/auth.test.js`: ```js title="./tests/auth.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); // User mock data const mockUserData = { username: 'tester', email: 'tester@strapi.com', provider: 'local', password: '1234abc', confirmed: true, blocked: null, }; it('should login user and return JWT token', async () => { await strapi.plugins['users-permissions'].services.user.add({ ...mockUserData, }); await request(strapi.server.httpServer) .post('/api/auth/local') .set('accept', 'application/json') .set('Content-Type', 'application/json') .send({ identifier: mockUserData.email, password: mockUserData.password, }) .expect('Content-Type', /json/) .expect(200) .then((data) => { expect(data.body.jwt).toBeDefined(); }); }); ``` 你可以使用返回的 JWT 令牌对 API 发起经过身份验证的请求。使用此示例,你可以添加更多测试以验证身份验证和授权是否按预期工作。 🌐 You can use the JWT token returned to make authenticated requests to the API. Using this example, you can add more tests to validate that the authentication and authorization are working as expected. ## 具有用户权限的高级API测试 {#advanced-api-testing-with-user-permissions} 🌐 Advanced API testing with user permissions 当你创建 API 测试时,你很可能需要测试需要身份验证的端点。在以下示例中,我们将实现一个辅助工具来获取和使用 JWT 令牌。 🌐 When you create API tests, you will most likely need to test endpoints that require authentication. In the following example we will implement a helper to get and use the JWT token. 创建 `tests/user.test.js`: 🌐 Create `tests/user.test.js`: ```js title="./tests/user.test.js" const { setupStrapi, cleanupStrapi } = require('./strapi'); const request = require('supertest'); beforeAll(async () => { await setupStrapi(); }); afterAll(async () => { await cleanupStrapi(); }); let authenticatedUser = {}; // User mock data const mockUserData = { username: 'tester', email: 'tester@strapi.com', provider: 'local', password: '1234abc', confirmed: true, blocked: null, }; describe('User API', () => { beforeAll(async () => { await strapi.plugins['users-permissions'].services.user.add({ ...mockUserData, }); const response = await request(strapi.server.httpServer) .post('/api/auth/local') .set('accept', 'application/json') .set('Content-Type', 'application/json') .send({ identifier: mockUserData.email, password: mockUserData.password, }); authenticatedUser.jwt = response.body.jwt; authenticatedUser.user = response.body.user; }); it('should return users data for authenticated user', async () => { await request(strapi.server.httpServer) .get('/api/users/me') .set('accept', 'application/json') .set('Content-Type', 'application/json') .set('Authorization', 'Bearer ' + authenticatedUser.jwt) .expect('Content-Type', /json/) .expect(200) .then((data) => { expect(data.body).toBeDefined(); expect(data.body.id).toBe(authenticatedUser.user.id); expect(data.body.username).toBe(authenticatedUser.user.username); expect(data.body.email).toBe(authenticatedUser.user.email); }); }); }); ``` ## 使用 GitHub Actions 自动化测试 {#automate-tests-with-github-actions} 🌐 Automate tests with GitHub Actions 更进一步,你可以使用 在每次推送和拉取请求时自动运行你的Jest测试套件。在你的项目中创建一个`.github/workflows/test.yaml`文件,并按如下方式添加工作流: ```yaml title="./.github/workflows/test.yaml" name: 'Tests' on: pull_request: push: jobs: run-tests: name: Run Tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Install modules run: npm ci - name: Run Tests run: npm run test ``` 将持续集成与单元测试和 API 测试相结合,有助于在回归测试进入生产环境之前防止其发生。 🌐 Pairing continuous integration with your unit and API tests helps prevent regressions before they reach production. # TypeScript Source: https://docs.strapi.io/cms/typescript # TypeScript - 使用提供的 [conversion](/cms/typescript/adding-support-to-existing-project) 步骤为现有的 Strapi 项目添加 TypeScript 支持。
:::strapi What to do next? - 了解基于 TypeScript 的 Strapi 项目的[结构](/cms/project-structure) - 了解与 TypeScript 相关的 [配置选项](/cms/configurations/typescript) - 深入了解 TypeScript 相关开发 [选项和功能](/cms/typescript/development) - 阅读特定用例的[指南](/cms/typescript/guides) ::: # TypeScript 开发 Source: https://docs.strapi.io/cms/typescript/development # 使用 Strapi 的 TypeScript 开发 {#typescript-development-with-strapi} 🌐 TypeScript development with Strapi 在使用 Strapi 开发基于 [TypeScript](/cms/typescript) 的应用时,你可以: 🌐 While developing a [TypeScript](/cms/typescript)-based application with Strapi, you can: - 使用自动补齐访问 [`Strapi`](#use-strapi-typescript-typings) 类的类型定义, - [为你的项目内容类型生成 typings](#generate-typings-for-content-types-schemas), - [以编程方式启动 Strapi](#start-strapi-programmatically), - 并遵循一些针对 [插件开发](#develop-a-plugin-using-typescript) 的 TypeScript 特定指令。 :::strapi Documents and entries 有关如何在基于 TypeScript 的项目中操作文档和条目的更多信息和最佳实践,请参阅 [专门指南](/cms/typescript/documents-and-entries)。 🌐 More information and best practices on how to manipulate documents and entries with a TypeScript-based project can be found in the [dedicated guide](/cms/typescript/documents-and-entries). ::: ## 使用 `Strapi` TypeScript 类型定义 {#use-strapi-typescript-typings} 🌐 Use `Strapi` TypeScript typings Strapi 在 `Strapi` 类上提供了类型定义,以增强 TypeScript 的开发体验。这些类型定义带有自动补齐功能,可以在开发时自动提供建议。 🌐 Strapi provides typings on the `Strapi` class to enhance the TypeScript development experience. These typings come with an autocomplete feature that automatically offers suggestions while developing. 要在开发 Strapi 应用时体验基于 TypeScript 的自动补齐功能,你可以尝试以下操作: 🌐 To experience TypeScript-based autocomplete while developing Strapi applications, you could try the following: 1. 从你的代码编辑器中打开 `./src/index.ts` 文件。 2. 从 `@strapi/strapi` 导入 `Core` 类型,并在全局 `register` 方法中将 `strapi` 参数声明为类型 `Core.Strapi`: ```typescript title="./src/index.ts" import type { Core } from '@strapi/strapi'; export default { register({ strapi }: { strapi: Core.Strapi }) { // ... }, }; ``` 3. 在 `register` 方法的主体中,开始输入 `strapi.` 并使用键盘箭头浏览可用属性。 4. 从列表中选择 `runLifecyclesFunctions`。 5. 当添加 `strapi.runLifecyclesFunctions` 方法时,代码编辑器会返回一个可用生命周期类型的列表(即 `register`、`bootstrap` 和 `destroy`)。使用键盘箭头选择其中一个生命周期,代码将自动补齐。 ## 为内容类型模式生成类型定义 {#generate-typings-for-content-types-schemas} 🌐 Generate typings for content-types schemas 要为你的项目模式生成类型,请使用 [`ts:generate-types` CLI 命令](/cms/cli#strapi-ts)。`ts:generate-types` 命令会在项目根目录下创建 `types` 文件夹,用于存储项目的类型。可选的 `--debug` 标志会返回生成的模式的详细表格。 🌐 To generate typings for your project schemas use the [`ts:generate-types` CLI command](/cms/cli#strapi-ts). The `ts:generate-types` command creates the folder `types`, at the project root, which stores the typings for your project. The optional `--debug` flag returns a detailed table of the generated schemas. 要使用 `ts:generate-types`,请在项目根目录的终端中运行以下代码: 🌐 To use `ts:generate-types`run the following code in a terminal at the project root: :::tip Tip: Automatically generate types 可以通过在 [ `config/typescript.js|ts` 配置文件](/cms/configurations/typescript#strapi-specific-configuration-for-typescript) 中添加 `autogenerate: true` 来在服务器重启时自动生成类型。 🌐 Types can be automatically generated on server restart by adding `autogenerate: true` to [the `config/typescript.js|ts` configuration file](/cms/configurations/typescript#strapi-specific-configuration-for-typescript). ::: :::tip Tip: Using types in your front-end application 要在前端应用中使用 Strapi 类型,你可以 直到 Strapi 实现官方解决方案。 ::: ### 修复生成类型的构建问题 {#fix-build-issues-with-the-generated-types} 🌐 Fix build issues with the generated types 可以排除生成的类型,以便实体服务不使用它们,而是使用不检查内容类型中可用的实际属性的宽松类型。 🌐 The generated types can be excluded so that the Entity Service doesn't use them and falls back on looser types that don't check the actual properties available in the content types. 要做到这一点,编辑 Strapi 项目的 `tsconfig.json` 并将 `types/generated/**` 添加到 `exclude` 数组中: 🌐 To do that, edit the `tsconfig.json` of the Strapi project and add `types/generated/**` to the `exclude` array: ```json title="./tsconfig.json" // ... "exclude": [ "node_modules/", "build/", "dist/", ".cache/", ".tmp/", ".strapi/", "src/admin/", "**/*.test.ts", "src/plugins/**", "types/generated/**" ] // ... ``` 然而,如果你仍然想在项目中使用生成的类型,但不希望 Strapi 使用它们,一个可行的解决方法是将这些生成的类型复制并粘贴到 `generated` 目录之外(这样在重新生成类型时,它们不会被覆盖),并从文件底部删除 `declare module '@strapi/types'`。 🌐 However, if you still want to use the generated types on your project, but don't want Strapi to use them, a workaround could be to copy those generated types and paste them outside of the `generated` directory (so that they aren't overwritten when the types are regenerated) and remove the `declare module '@strapi/types'` from the bottom of the file. :::warning 类型应仅从 `@strapi/strapi` 导入以避免破坏性更改。`@strapi/types` 中的类型仅供内部使用,可能会在没有通知的情况下更改。 🌐 Types should only be imported from `@strapi/strapi` to avoid breaking changes. The types in `@strapi/types` are for internal use only and may change without notice. ::: ## 以编程方式启动 Strapi {#start-strapi-programmatically} 🌐 Start Strapi programmatically 要在 TypeScript 项目中以编程方式启动 Strapi,Strapi 实例需要指定已编译代码的位置。本节介绍如何设置和指明已编译代码目录。 🌐 To start Strapi programmatically in a TypeScript project the Strapi instance requires the compiled code location. This section describes how to set and indicate the compiled code directory. ### 使用 `strapi()` 工厂 {#use-the-createstrapi-factory} 🌐 Use the `strapi()` factory 可以通过使用 `strapi()` 工厂以编程方式运行 Strapi。由于 TypeScript 项目的代码会被编译到特定目录,因此应将参数 `distDir` 传递给工厂,以指示应从哪里读取已编译的代码: 🌐 Strapi can be run programmatically by using the `strapi()` factory. Since the code of TypeScript projects is compiled in a specific directory, the parameter `distDir` should be passed to the factory to indicate where the compiled code should be read: ```js title="./server.js" const strapi = require('@strapi/strapi'); const app = strapi.createStrapi({ distDir: './dist' }); app.start(); ``` ### 使用 `strapi.compile()` 函数 {#use-the-strapicompile-function} 🌐 Use the `strapi.compile()` function `strapi.compile()` 函数主要用于开发需要启动 Strapi 实例并检测项目是否包含 TypeScript 代码的工具。`strapi.compile()` 会自动检测项目语言。如果项目代码包含任何 TypeScript 代码,`strapi.compile()` 会编译代码并返回一个上下文,其中包含 Strapi 所需目录的特定值: 🌐 The `strapi.compile()` function should be mostly used for developing tools that need to start a Strapi instance and detect whether the project includes TypeScript code. `strapi.compile()` automatically detects the project language. If the project code contains any TypeScript code, `strapi.compile()` compiles the code and returns a context with specific values for the directories that Strapi requires: ```js const strapi = require('@strapi/strapi'); strapi.compile().then(appContext => strapi(appContext).start()); ``` ## 使用 TypeScript 开发插件 {#develop-a-plugin-using-typescript} 🌐 Develop a plugin using TypeScript 可以按照[插件开发文档](/cms/plugins-development/developing-plugins)生成新插件,确保在CLI工具提示时选择“TypeScript”。 🌐 New plugins can be generated following the [plugins development documentation](/cms/plugins-development/developing-plugins), ensuring you select "TypeScript" when prompted by the CLI tool. TypeScript 应用有两个重要的区别: 🌐 There are 2 important distinctions for TypeScript applications: - 创建插件后,在插件目录 `src/admin/plugins/[my-plugin-name]` 中运行 `yarn` 或 `npm install` 来安装插件的依赖。 - 在插件目录 `src/admin/plugins/[my-plugin-name]` 中运行 `yarn build` 或 `npm run build` 来构建包含该插件的管理面板。 :::note 在初次安装后,无需重复执行 `yarn` 或 `npm install` 命令。执行 `yarn build` 或 `npm run build` 命令是实现任何影响管理面板的插件开发所必需的。 🌐 It is not necessary to repeat the `yarn` or `npm install` command after the initial installation. The `yarn build` or `npm run build` command is necessary to implement any plugin development that affects the admin panel. ::: # TypeScript 指南 Source: https://docs.strapi.io/cms/typescript/guides # TypeScript 指南 {#typescript-guides} 🌐 TypeScript guides 以下指南将帮助你了解基于 [Typescript](/cms/typescript) 的 Strapi 项目的具体方面。 🌐 The following guides will help you on specific aspects of a [Typescript-based](/cms/typescript) Strapi project. # 升级工具 Source: https://docs.strapi.io/cms/upgrade-tool # 升级工具 {#upgrade-tool} 🌐 Upgrade tool 升级工具帮助 Strapi 用户将其 Strapi 应用依赖和代码升级到特定版本。 🌐 The upgrade tool assists Strapi users in upgrading their Strapi application dependencies and code to a specific version. 运行升级工具会触发应用依赖的更新、安装,以及执行一系列**代码修改工具(codemods)**