后端定制 Back-end customization

Strapi 后端的所有元素,如路由、策略、中间件、控制器、服务、模型、请求、响应和 webhook,都可以定制。

歧义:Strapi 后端

作为无头 CMS,Strapi 软件整体可视为您的网站或应用程序的“后端”。 但 Strapi 软件本身包含 2 个不同部分:

  • Strapi 的 后端 部分是 Strapi 运行的 HTTP 服务器。与任何 HTTP 服务器一样,Strapi 后端接收请求并发送响应。您的内容存储在数据库中,Strapi 后端与数据库交互以创建、检索、更新和删除内容。
  • Strapi 的 前端 部分称为管理面板。管理面板提供图形用户界面来帮助您构建和管理内容。

在整个开发人员文档中,“后端”仅指 Strapi 的后端部分。

用户指南 介绍了如何使用管理面板,管理面板自定义部分 详细介绍了管理面板可用的各种自定义选项。

Strapi 后端运行基于 Koa(后端 JavaScript 框架)的 HTTP 服务器。

与任何 HTTP 服务器一样,Strapi 后端接收请求并发送响应。您可以通过 RESTGraphQL API 向 Strapi 后端发送请求以创建、检索、更新或删除数据。

请求可以按如下方式通过 Strapi 后端:

  1. Strapi 服务器接收 请求
  2. 请求命中按顺序运行的 全局中间件
  3. 请求命中 路由
    默认情况下,Strapi 会为您创建的所有内容类型生成路由文件(请参阅 REST API 文档),并且可以添加和配置更多路由。
  4. 路由策略 充当只读验证步骤,可以阻止对路由的访问。路由中间件 可以控制请求流并在继续前进之前改变请求本身。
  5. 控制器 在到达路由后执行代码。 服务 是可选的附加代码,可用于构建可由控制器重用的自定义逻辑。
  6. 控制器和服务执行的代码与 模型 交互,后者是存储在数据库中的内容数据结构的表示。
    与模型所表示的数据的交互由 实体服务查询引擎 处理。
  7. 服务器返回 响应。响应可以在发送之前通过路由中间件和全局中间件返回。

全局和路由中间件都包含一个异步回调函数 await next()。根据中间件返回的内容,请求将通过后端的较短或较长路径:

  • 如果中间件未返回任何内容,请求将继续通过后端的各个核心元素(即控制器、服务以及与数据库交互的其他层)。
  • 如果中间件在调用 await next() 之前返回,则将立即发送响应,跳过其余核心元素。然后它将返回到它出现的同一链。

请注意,本节页面中描述的所有自定义仅适用于 REST API。GraphQL 自定义 在 GraphQL 插件文档中描述。

通过示例学习

如果您更喜欢通过阅读示例来学习并了解它们如何在实际用例中使用,示例手册 部分是查看 Strapi 后端自定义工作原理的另一种方式。

交互式图表

下图表示请求如何通过 Strapi 后端。您可以单击任何形状以跳转到文档中的相关页面。

mermaid
graph TB
  request[Request] ---> globalMiddlewareA(("Global middleware<br/>before await next()"))
  globalMiddlewareA --"Call next()"--> routePolicy{Route policy}
  globalMiddlewareA --"Returns before next()<br>Goes back up in the middleware chain"-->globalMiddlewareB
  routePolicy --Returns true--> routeMiddlewareA(("Route middleware<br/>before await next()"))
  routePolicy --Returns false or an error-->globalMiddlewareB
  routeMiddlewareA --"Returns before next()<br>Goes back up in the middleware chain"-->routeMiddlewareB
  routeMiddlewareA --"Call next()"--> controllerA{{Controller}}
  controllerA --"Call Service(s)"--> serviceA{{Service}}
  controllerA --"Don't call Service(s)" --> routeMiddlewareB
  serviceA --"Call Entity Service" --> entityService{{Entity Service}}
  serviceA --"Don't call Entity Service" --> controllerB
  entityService --"Call Query Engine"--> queryEngine{{Query Engine}}
  entityService --"Don't call Query Engine" --> serviceB
  queryEngine --> lifecyclesBefore[/Lifecycle<br> beforeX\]
  lifecyclesBefore[/Lifecycle<br> beforeX\] --> database[(Database)]
  database --> lifecyclesAfter[\Lifecycle<br> afterX/]
  lifecyclesAfter --> serviceB{{"Service<br/>after Entity Service call"}}
  serviceB --> controllerB{{"Controller<br/>after service call"}}
  controllerB --> routeMiddlewareB(("Route middleware<br/>after await next()"))
  routeMiddlewareB --> globalMiddlewareB(("Global middleware<br/>after await next()"))
  globalMiddlewareB --> response[Response]
  linkStyle 3 stroke:green,color:green
  linkStyle 4 stroke:red,color:red
  linkStyle 2 stroke:purple,color:purple
  linkStyle 5 stroke:purple,color:purple
  click request "/dev-docs/backend-customization/requests-responses"
  click globalMiddlewareA "/dev-docs/backend-customization/middlewares"
  click globalMiddlewareB "/dev-docs/backend-customization/middlewares"
  click routePolicy "/dev-docs/backend-customization/routes"
  click routeMiddlewareA "/dev-docs/backend-customization/routes"
  click routeMiddlewareB "/dev-docs/backend-customization/routes"
  click controllerA "/dev-docs/backend-customization/controllers"
  click controllerB "/dev-docs/backend-customization/controllers"
  click serviceA "/dev-docs/backend-customization/services"
  click serviceB "/dev-docs/backend-customization/services"
  click entityService "/dev-docs/api/entity-service/"
  click lifecyclesBefore "/dev-docs/backend-customization/models#lifecycle-hooks"
  click queryEngine "/dev-docs/api/query-engine/"
  click lifecyclesAfter "/dev-docs/backend-customization/models#lifecycle-hooks"
  click response "/dev-docs/backend-customization/requests-responses"
  click queryEngine "/dev-docs/api/query-engine"