Skip to main content

服务器 API:获取器与使用

🌐 Server API: Getters & usage

Page summary:

通过顶层 getter (strapi.plugin('my-plugin').service('name')) 或全局 getter (strapi.service('plugin::my-plugin.name')) 访问插件资源。两者返回相同的对象。在自己的插件中使用顶层 getter,在应用代码或其他插件中使用全局 getter。路由没有全局 getter 的对应项。配置使用专用的配置 API。

插件服务器资源,例如控制器、服务、策略、中间件和内容类型,可以通过 strapi 实例从任何服务器端位置访问:其他插件、生命周期钩子、应用控制器或自定义脚本。路由和配置使用专用的 API — 请参见下面的 getter 参考

🌐 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 below.

Prerequisites

在深入了解本页的概念之前,请确保你已经:

🌐 Before diving deeper into the concepts on this page, please ensure you have:

Getter 风格

🌐 Getter styles

Strapi 提供两种访问插件资源的方式。两者返回相同的底层对象,唯一的区别只是语法上的。

🌐 Strapi exposes 2 styles for accessing plugin resources. Both return the same underlying object, the difference is purely syntactic.

顶层 getter 通过插件名称链式调用:

strapi.plugin('plugin-name').service('service-name')
strapi.plugin('plugin-name').controller('controller-name')

全局获取器 直接在 strapi 实例上使用完整 UID:

strapi.service('plugin::plugin-name.service-name')
strapi.controller('plugin::plugin-name.controller-name')

选择取决于具体情况和可读性:

🌐 The choice is a matter of context and readability:

  • 在你自己的插件中,顶层 getter 更简洁,并使插件边界更加明确。
  • 从应用代码或另一个插件中,全局 getter 与 api:: UID 一起使用时读起来更自然。

2 个资源是例外:

  • routes(strapi.plugin('plugin-name').routes)没有全局 getter 等价物,
  • 并且配置使用专用的配置 API(strapi.plugin('plugin-name').config()strapi.config.get(...)),而不是资源获取器。

完整的 getter 引用

🌐 Full getter reference

下表列出了名为 todo、资源名为 task 的插件的所有可用获取器:

🌐 The following table lists all available getters for a plugin named todo with a resource named task: | | 服务 | 控制器 | 内容类型 | 策略 | 中间件 | 路由 | 配置 || --- | --- | --- | --- | --- | --- | --- | --- || 顶层 | strapi.plugin('todo').service('task') | strapi.plugin('todo').controller('task') | strapi.plugin('todo').contentType('task') | strapi.plugin('todo').policy('is-owner') | strapi.plugin('todo').middleware('audit-log') | strapi.plugin('todo').routes | strapi.plugin('todo').config('featureFlag') || 全局 | strapi.service('plugin::todo.task') | strapi.controller('plugin::todo.task') | strapi.contentType('plugin::todo.task') | strapi.policy('plugin::todo.is-owner') | strapi.middleware('plugin::todo.audit-log') | — | strapi.config.get('plugin::todo.featureFlag') |

这两种风格返回相同的底层对象。路由没有全局 getter 的对应物。配置使用专用的配置 API 而不是资源 getter,这两种形式读取的都是相同的合并值。

🌐 Both styles return the same underlying object. Routes have no global getter equivalent. Configuration uses dedicated config APIs rather than resource getters, both forms read the same merged value.

Tip

运行 yarn strapi consolenpm run strapi console 来在实时控制台中检查 strapi 对象,并以交互方式探索可用的插件及其资源。

🌐 Run yarn strapi console or npm run strapi console to inspect the strapi object in a live console and explore available plugins and their resources interactively.

使用示例

🌐 Usage examples

从控制器调用插件服务

🌐 Calling a plugin service from a controller

最常见的模式:控制器委托给它自己插件的服务:

🌐 The most common pattern: a controller delegates to its own plugin's service:

/src/plugins/todo/server/src/controllers/task.js
'use strict';

module.exports = ({ strapi }) => ({
async find(ctx) {
const tasks = await strapi.plugin('todo').service('task').findAll(); // top-level getter: preferred inside your own plugin
ctx.body = tasks;
},

async create(ctx) {
const task = await strapi
.plugin('todo')
.service('task')
.create(ctx.request.body);
ctx.status = 201;
ctx.body = task;
},
});

从 bootstrap 调用插件服务

🌐 Calling a plugin service from bootstrap

bootstrap() 中调用的服务可以访问完整的 strapi 实例,包括其他插件的服务:

🌐 Services called in bootstrap() have access to the full strapi instance, including other plugins' services:

/src/plugins/todo/server/src/bootstrap.js
'use strict';

module.exports = async ({ strapi }) => {
// Call own plugin service to seed initial data
const count = await strapi.plugin('todo').service('task').count();

if (count === 0) {
await strapi.plugin('todo').service('task').create({
title: 'Welcome task',
done: false,
});
}
};

在插件之间或从应用代码中调用

🌐 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:

/src/api/project/controllers/project.js
'use strict';

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::project.project', ({ strapi }) => ({
async create(ctx) {
const { data, meta } = await super.create(ctx);

await strapi.service('plugin::todo.task').create({ // global getter: preferred in application code
title: `Review project: ${data.attributes.name}`,
done: false,
});

return { data, meta };
},
}));

在运行时读取插件配置

🌐 Reading plugin configuration at runtime

// Read a single key
const maxItems = strapi.plugin('todo').config('maxItems');
// Read the full config object
const todoConfig = strapi.config.get('plugin::todo');
// Read a nested key
const endpoint = strapi.config.get('plugin::todo.endpoint');
Note

strapi.plugin('my-plugin').config('key') 读取合并后的配置(用户覆盖应用在插件默认值之上)。这是在插件代码中读取配置的推荐方式。有关插件配置如何声明和合并,请参阅 服务器配置

访问内容类型架构

🌐 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:

// Access the content-type schema
const schema = strapi.contentType('plugin::todo.task');

const sanitizedOutput = await strapi.contentAPI.sanitize.output(
data,
schema,
{ auth: ctx.state.auth }
);

常见错误

🌐 Common errors

  • 路由处理程序与控制器键命名不匹配。 如果你的路由声明了 handler: 'task.find',你的控制器索引必须导出一个名为 task 的键,并且该控制器必须有一个名为 find 的方法。当路由匹配时,如果不匹配会抛出运行时错误。

  • 滥用策略上下文参数。 策略函数的第一个参数是一个策略上下文对象,而不是原生的 Koa ctx。它封装了请求上下文,但提供了不同的接口。在你的代码中将它命名为 ctx 不会导致错误,但将其当作 Koa 上下文处理(例如,调用 ctx.bodyctx.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

  • 在你自己的插件中优先使用顶层 getter。 当两者都在同一个插件中时,strapi.plugin('my-plugin').service('task') 比全局形式更易读。
  • 在应用代码和跨插件调用中使用全局 getter。 当从 src/api/ 调用或从另一个插件调用时,使用完整的 UID plugin::todo.task 可以明确依赖,并且更容易搜索。
  • 在使用服务时访问服务,而不是在声明时。 避免在模块初始化时在闭包中捕获服务引用。始终在调用时使用 getter 解析它们,以确保 Strapi 完全加载。