中间件定制
¥Middlewares customization
在 Strapi 中,3 个中间件概念共存:
¥In Strapi, 3 middleware concepts coexist:
-
整个 Strapi 服务器应用的全局中间件是 配置并启用。这些中间件可以应用于应用级别或 API 级别。
当前文档描述了如何实现它们。
插件还可以添加全局中间件(参见 服务器 API 文档)。¥Global middlewares are configured and enabled for the entire Strapi server application. These middlewares can be applied at the application level or at the API level.
The present documentation describes how to implement them.
Plugins can also add global middlewares (see Server API documentation). -
路由中间件的范围更有限,并且在路由级别被配置和用作中间件。它们在 路由文档 中进行了描述。
¥Route middlewares have a more limited scope and are configured and used as middlewares at the route level. They are described in the routes documentation.
-
文档服务中间件适用于文档服务 API,并具有自己的 implementation 和相关的 生命周期钩子。
¥Document Service middlewares apply to the Document Service API and have their own implementation and related lifecycle hooks.
执行
¥Implementation
可以实现新的应用级或 API 级中间件:
¥A new application-level or API-level middleware can be implemented:
-
¥with the interactive CLI command
strapi generate
-
或通过在适当的文件夹中手动创建 JavaScript 文件(参见 项目结构):
¥or manually by creating a JavaScript file in the appropriate folder (see project structure):
-
./src/middlewares/
用于应用级中间件¥
./src/middlewares/
for application-level middlewares -
./src/api/[api-name]/middlewares/
用于 API 级中间件¥
./src/api/[api-name]/middlewares/
for API-level middlewares -
./src/plugins/[plugin-name]/middlewares/
换 插件中间件¥
./src/plugins/[plugin-name]/middlewares/
for plugin middlewares
-
使用 REST API 的中间件具有如下功能:
¥Middlewares working with the REST API are functions like the following:
- JavaScript
- TypeScript
module.exports = (config, { strapi })=> {
return (context, next) => {};
};
export default (config, { strapi })=> {
return (context, next) => {};
};
全局范围的自定义中间件应添加到 中间件配置文件 中,否则 Strapi 将不会加载它们。
¥Globally scoped custom middlewares should be added to the middlewares configuration file 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:
module.exports = {
routes: [
{
method: "GET",
path: "/[collection-name]",
handler: "[controller].find",
config: {
middlewares: ["[middleware-name]"],
// See the usage section below for middleware naming conventions
},
},
],
};
Example of a custom timer middleware
- JavaScript
- TypeScript
module.exports = () => {
return async (ctx, next) => {
const start = Date.now();
await next();
const delta = Math.ceil(Date.now() - start);
ctx.set('X-Response-Time', delta + 'ms');
};
};
export default () => {
return async (ctx, next) => {
const start = Date.now();
await next();
const delta = Math.ceil(Date.now() - start);
ctx.set('X-Response-Time', delta + 'ms');
};
};
GraphQL 插件还允许使用不同语法的 实现自定义中间件。
¥The GraphQL plugin also allows implementing custom middlewares, with a different syntax.
用法
¥Usage
中间件根据其范围有不同的调用方式:
¥Middlewares are called different ways depending on their scope:
-
将
global::middleware-name
用于应用级中间件¥use
global::middleware-name
for application-level middlewares -
使用
api::api-name.middleware-name
作为 API 级中间件¥use
api::api-name.middleware-name
for API-level middlewares -
使用
plugin::plugin-name.middleware-name
作为插件中间件¥use
plugin::plugin-name.middleware-name
for plugin middlewares
要列出所有已注册的中间件,请运行 yarn strapi middlewares:list
。
¥To list all the registered middlewares, run yarn strapi middlewares:list
.
使用 "是所有者政策" 限制内容访问
¥Restricting content access with an "is-owner policy"
通常要求条目的作者是唯一允许编辑或删除该条目的用户。在以前版本的 Strapi 中,这被称为 "是所有者政策"。对于 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:
-
在项目文件夹中,通过在终端中运行
yarn strapi generate
(或npm run strapi generate
)命令,使用 Strapi CLI 生成器创建中间件。¥From your project's folder, create a middleware with the Strapi CLI generator, by running the
yarn strapi generate
(ornpm run strapi generate
) command in the terminal. -
使用键盘箭头从列表中选择
middleware
,然后按 Enter。¥Select
middleware
from the list, using keyboard arrows, and press Enter. -
为中间件命名,例如
isOwner
。¥Give the middleware a name, for instance
isOwner
. -
从列表中选择
Add middleware to an existing API
。¥Choose
Add middleware to an existing API
from the list. -
选择你希望中间件应用哪个 API。
¥Select which API you want the middleware to apply.
-
将
/src/api/[your-api-name]/middlewares/isOwner.js
文件中的代码替换为以下内容,将第 22 行中的api::restaurant.restaurant
替换为与你在步骤 5 中选择的 API 对应的标识符(例如,如果你的 API 名称是blog-post
,则为api::blog-post.blog-post
):¥Replace the code in the
/src/api/[your-api-name]/middlewares/isOwner.js
file with the following, replacingapi::restaurant.restaurant
in line 22 with the identifier corresponding to the API you choose at step 5 (e.g.,api::blog-post.blog-post
if your API name isblog-post
):
"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();
}
};
};
-
确保中间件配置为应用于某些路由。在
src/api/[your-api–name]/routes/[your-content-type-name].js
文件中的config
对象中,定义你希望中间件应用的方法 (create
、read
、update
、delete
),并为这些路由声明isOwner
中间件。
例如,如果你希望允许任何用户对restaurant
API 中的restaurant
内容类型进行 GET(即read
方法)和 POST(即create
方法)请求,但希望将 PUT(即update
方法)和 DELETE 请求限制为仅对创建条目的用户,你可以在src/api/restaurant/routes/restaurant.js
文件中使用以下代码:¥Ensure the middleware is configured to apply on some routes. In the
config
object found in thesrc/api/[your-api–name]/routes/[your-content-type-name].js
file, define the methods (create
,read
,update
,delete
) for which you would like the middleware to apply, and declare theisOwner
middleware for these routes.
For instance, if you wish to allow GET (i.e.,read
method) and POST (i.e.,create
method) requests to any user for therestaurant
content-type in therestaurant
API, but would like to restrict PUT (i.e.,update
method) and DELETE requests only to the user who created the entry, you could use the following code in thesrc/api/restaurant/routes/restaurant.js
file: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"],
},
},
});
你可以在 路由文档.h 中找到有关路由中间件的更多信息。
¥You can find more information about route middlewares in the routes documentation.