中间件配置
页面摘要:
/config/middlewares用于对全局中间件排序、启用自定义名称或解析路径,并暴露内置的配置选项。
在 Strapi 中,有 3 种中间件概念并存:
-
全局中间件为整个 Strapi 服务器应用配置并启用。这些中间件可以在应用层面或 API 层面应用。 本文档介绍如何实现它们。 插件也可以添加全局中间件(参见 Server API 文档)。
-
路由中间件作用域更有限,在路由层面配置并使用为中间件。它们在路由文档中描述。
-
Document Service 中间件应用于 Document Service API,有自己的实现和相关生命周期钩子。
./config/middlewares.js 文件用于定义 Strapi 服务器应应用的所有全局中间件。
只有出现在 ./config/middlewares.js 中的中间件才会被应用。中间件的加载遵循特定的加载顺序,并对每个中间件有某些命名约定和可选配置。
Strapi 会预先填充 ./config/middlewares.js 文件,其中包含内置的内部中间件,每个都有自己的配置选项。
加载顺序
./config/middlewares.js 文件导出一个数组,其中顺序很重要,并控制中间件栈的执行顺序:
JavaScript
module.exports = [
// 该数组预填充了以 `strapi::` 为前缀的内置内部中间件
'strapi::logger',
'strapi::errors',
'strapi::security',
'strapi::cors',
// 不需要任何配置的自定义中间件
'global::my-custom-node-module',
// 用于查找包或路径的自定义名称
{
name: 'my-custom-node-module',
config: {
foo: 'bar',
},
},
// 用于查找包或路径的自定义 resolve
{
resolve: '../some-dir/custom-middleware',
config: {
foo: 'bar',
},
},
// 内部中间件的自定义配置
{
name: 'strapi::poweredBy',
config: {
poweredBy: 'Some awesome company',
},
},
// 其余的内部与内置中间件
'strapi::query',
'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
];
TypeScript
export default [
// 该数组预填充了以 `strapi::` 为前缀的内置内部中间件
'strapi::logger',
'strapi::cors',
'strapi::body',
'strapi::errors',
// ...
'my-custom-node-module', // 不需要任何配置的自定义中间件
{
// 用于查找包或路径的自定义名称
name: 'my-custom-node-module',
config: {
foo: 'bar',
},
},
{
// 用于查找包或路径的自定义 resolve
resolve: '../some-dir/custom-middleware',
config: {
foo: 'bar',
},
},
];
如果你不确定将中间件放在栈中的什么位置,请将其添加到列表末尾。
命名约定
全局中间件可以根据其来源分为不同类型,这定义了以下命名约定:
| Middleware type | Origin | Naming convention |
|---|---|---|
| Internal | 内置中间件(即随 Strapi 一起提供),自动加载 | strapi::middleware-name |
| Application-level | 从 ./src/middlewares 文件夹加载 | global::middleware-name |
| API-level | 从 ./src/api/[api-name]/middlewares 文件夹加载 | api::api-name.middleware-name |
| Plugin | 从插件接口的 middlewares 属性 的 strapi-server.js 导出 | plugin::plugin-name.middleware-name |
| External | 可以是: |
- 通过 npm 安装的 node 模块
- 或本地中间件(即在
./config/middlewares.js中创建的自定义中间件并配置)。 | -
由于它们直接从配置文件中配置和解析,因此没有命名约定。 |
可选配置
中间件可以有一个可选配置,包含以下参数:
| Parameter | Description | Type |
|---|---|---|
config | 用于定义或覆盖中间件配置 | Object |
resolve | 中间件文件夹的路径(用于外部中间件很有用) | String |
内部中间件配置参考
Strapi 的核心包含以下内部中间件,主要用于性能、安全和错误处理:
| Middleware | Added by Default | Required |
|---|---|---|
| body | Yes | Yes |
| compression | No | No |
| cors | Yes | Yes |
| errors | Yes | Yes |
| favicon | Yes | Yes |
| ip | No | No |
| logger | Yes | No |
| poweredBy | Yes | No |
| query | Yes | Yes |
| response-time | No | No |
| responses | Yes | Yes |
| public | Yes | Yes |
| security | Yes | Yes |
| session | Yes | No |
body
body 中间件基于 koa-body。它使用 node-formidable 库来处理文件。body 接受以下选项:
| Option | Description | Type | Default |
|---|---|---|---|
multipart | 解析 multipart 请求体 | Boolean | true |
patchKoa | 将请求体修补到 Koa 的 ctx.request | Boolean | true |
jsonLimit | JSON 请求体的字节限制(如果是整数) | String or Integer | 1mb |
formLimit | 表单请求体的字节限制(如果是整数) | String or Integer | 56kb |
textLimit | 文本请求体的字节限制(如果是整数) | String or Integer | 56kb |
encoding | 设置传入表单字段的编码 | String | utf-8 |
formidable | 传递给 formidable multipart 解析器的选项(参见 node-formidable 文档)。 | Object | undefined |
有关 koa-body 可用选项的完整列表,请查看 koa-body 文档。
** 示例:body 中间件的自定义配置 **
JavaScript
module.exports = [
// ...
{
name: 'strapi::body',
config: {
jsonLimit: '3mb',
formLimit: '10mb',
textLimit: '256kb',
encoding: 'gbk',
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::body',
config: {
jsonLimit: '3mb',
formLimit: '10mb',
textLimit: '256kb',
encoding: 'gbk',
},
},
// ...
]
compression
compression 中间件基于 koa-compress。它接受以下选项:
| Option | Description | Type | Default |
|---|---|---|---|
threshold | 要压缩的最小响应大小(字节) | String or Integer | 1kb |
br | 切换 Brotli 压缩 | Boolean | true |
gzip | 切换 gzip 压缩 | Boolean | false |
deflate | 切换 deflate 压缩 | Boolean | false |
defaultEncoding | 指定对没有 Accept-Encoding 请求头的请求使用哪些编码器 | String | identity |
示例:compression 中间件的自定义配置
JavaScript
module.exports = [
// ...
{
name: 'strapi::compression',
config: {
br: false
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::compression',
config: {
br: false
},
},
// ...
]
cors
此安全中间件涉及跨源资源共享(CORS),基于 @koa/cors。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
origin | 配置 Access-Control-Allow-Origin 请求头 | String or Array or Function | '*' |
maxAge | 配置 Access-Control-Max-Age 请求头,单位为秒 | String or Number | 31536000 |
credentials | 配置 Access-Control-Allow-Credentials 请求头 | Boolean | true |
methods | 配置 Access-Control-Allow-Methods 请求头 | Array or String | ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'] |
headers | 配置 Access-Control-Allow-Headers 请求头 | Array or String | 传入 Access-Control-Request-Headers 的请求头 |
keepHeaderOnError | 如果抛出错误,将已设置的请求头添加到 err.header | Boolean | false |
** 示例:cors 中间件的自定义配置**
JavaScript
module.exports = [
// ...
{
name: 'strapi::cors',
config: {
origin: ['https://example.com', 'https://subdomain.example.com', 'https://someotherwebsite.org'],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
keepHeaderOnError: true,
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::cors',
config: {
origin: ['https://example.com', 'https://subdomain.example.com', 'https://someotherwebsite.org'],
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
headers: ['Content-Type', 'Authorization', 'Origin', 'Accept'],
keepHeaderOnError: true,
},
},
// ...
]
** 示例:将 cors 中间件作为参数的函数内的自定义配置**
origin 可以接受一个符合以下签名的 Function 作为参数
export default [
// ...
{
name: 'strapi::cors',
config: {
origin: (ctx): string | string[] => {
const origin = ctx.request.header.origin;
if (origin === 'http://localhost:3000') {
return origin; // 返回值将成为 Access-Control-Allow-Origin 请求头的一部分
}
return ''; // CORS 检查失败
}
},
},
// ...
]
errors
errors 中间件处理代码抛出的错误。根据错误类型,它将适当的 HTTP 状态设置到响应中。默认情况下,任何不应暴露给最终用户的错误都将导致 500 HTTP 响应。
该中间件没有任何配置选项。
favicon
favicon 中间件提供 favicon,基于 koa-favicon。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
path | favicon 文件的路径 | String | 'favicon.ico' |
maxAge | Cache-control max-age 指令,单位为毫秒 | Integer | 86400000 |
** 示例:favicon 中间件的自定义配置**
JavaScript
module.exports = [
// ...
{
name: 'strapi::favicon',
config: {
path: './public/uploads/custom-fav-abc123.ico'
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::favicon',
config: {
path: './public/uploads/custom-fav-abc123.ico'
},
},
// ...
]
ip
ip 中间件是一个基于 koa-ip 的 IP 过滤中间件。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
whitelist | 白名单 IP | Array | [] |
blacklist | 黑名单 IP | Array | [] |
whitelist 和 blacklist 选项支持通配符(例如 whitelist: ['192.168.0.*', '127.0.0.*'])和区间(例如 whitelist: ['192.168.*.[3-10]'])。
** 示例:ip 中间件的自定义配置**
JavaScript
module.exports = [
// ...
{
name: 'strapi::ip',
config: {
whitelist: ['192.168.0.*', '192.168.1.*', '123.123.123.123'],
blacklist: ['1.116.*.*', '103.54.*.*'],
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::ip',
config: {
whitelist: ['192.168.0.*', '192.168.1.*', '123.123.123.123'],
blacklist: ['1.116.*.*', '103.54.*.*'],
},
},
// ...
]
logger
logger 中间件用于记录请求日志。
要为 logger 中间件定义自定义配置,请创建一个专用配置文件(./config/logger.js)。它应导出一个对象,该对象必须是完整或部分 winstonjs logger 配置。该对象将在服务器启动时与 Strapi 的默认 logger 配置合并。
** 示例:logger 中间件的自定义配置**
JavaScript
'use strict';
const {
winston,
formats: { prettyPrint, levelFilter },
} = require('@strapi/logger');
module.exports = {
transports: [
new winston.transports.Console({
level: 'http',
format: winston.format.combine(
levelFilter('http'),
prettyPrint({ timestamps: 'YYYY-MM-DD hh:mm:ss.SSS' })
),
}),
],
};
TypeScript
'use strict';
const {
winston,
formats: { prettyPrint, levelFilter },
} = require('@strapi/logger');
export default {
transports: [
new winston.transports.Console({
level: 'http',
format: winston.format.combine(
levelFilter('http'),
prettyPrint({ timestamps: 'YYYY-MM-DD hh:mm:ss.SSS' })
),
}),
],
};
poweredBy
poweredBy 中间件向响应头添加一个 X-Powered-By 参数。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
poweredBy | X-Powered-By 请求头的值 | String | 'Strapi <strapi.io>' |
** 示例:poweredBy 中间件的自定义配置**
JavaScript
module.exports = [
// ...
{
name: 'strapi::poweredBy',
config: {
poweredBy: 'Some Awesome Company <example.com>'
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::poweredBy',
config: {
poweredBy: 'Some Awesome Company <example.com>'
},
},
// ...
]
query
query 中间件是一个基于 qs 的查询解析器。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
strictNullHandling | 区分 null 值和空字符串(参见 qs 文档) | Boolean | true |
arrayLimit | 解析数组时的最大索引限制(参见 qs 文档) | Number | 100 |
depth | 解析对象时嵌套对象的最大深度(参见 qs 文档) | Number | 20 |
查询字符串中的方括号风格数组(populate、fields、filters 以及嵌套键)使用 qs 和 arrayLimit 进行解析。当列表超出该限制时,qs 可能会产生对象形状的值而不是数组。Strapi 随后可能会拒绝该查询或返回不能指向此设置的错误。当你需要更长的列表时,请增大 arrayLimit。较大的值允许更长的查询字符串,并增加每次请求的解析工作量。
** 示例:query 中间件的自定义配置 **
JavaScript
module.exports = [
// ...
{
name: 'strapi::query',
config: {
arrayLimit: 50,
depth: 10,
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::query',
config: {
arrayLimit: 50,
depth: 10,
},
},
// ...
]
** 示例:为长 REST 查询列表提高 arrayLimit **
使用适合你最长方括号编码列表的值(例如许多 populate[n] 条目)。根据你的需求和可接受的解析开销调整该数字。
JavaScript
module.exports = [
// ...
{
name: 'strapi::query',
config: {
arrayLimit: 200,
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::query',
config: {
arrayLimit: 200,
},
},
// ...
]
response-time
response-time 中间件为响应头启用 X-Response-Time(单位为毫秒)。
该中间件没有任何配置选项。
public
public 中间件是一个静态文件服务中间件,基于 koa-static。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
maxAge | Cache-control max-age 指令,单位为毫秒 | Integer | 60000 |
在 config 中使用驼峰命名的 maxAge 键,与表格一致。Strapi 5 只从你的 strapi::public 中间件 config 中读取此字段,并将其传递给 koa-static(参见 packages/core/core/src/middlewares/public.ts);defer 在核心中间件内部是固定的,因此你无需在此设置它。
你可以通过编辑服务器配置文件来自定义 public 文件夹的路径。
示例:public 中间件的自定义配置
JavaScript
module.exports = [
// ...
{
name: 'strapi::public',
config: {
maxAge: 86400000, // 1 天(毫秒)
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::public',
config: {
maxAge: 86400000, // 1 天(毫秒)
},
},
// ...
]
security
security 中间件基于 koa-helmet。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
crossOriginEmbedderPolicy | 将 Cross-Origin-Embedder-Policy 请求头设为 require-corp | Boolean | false |
crossOriginOpenerPolicy | 设置 Cross-Origin-Opener-Policy 请求头 | Boolean | false |
crossOriginResourcePolicy | 设置 Cross-Origin-Resource-Policy 请求头 | Boolean | false |
originAgentCluster | 设置 Origin-Agent-Cluster 请求头 | Boolean | false |
contentSecurityPolicy | 设置 Content-Security-Policy 请求头 | Object | - |
xssFilter | 通过将 X-XSS-Protection 请求头设为 0 来禁用浏览器的跨站脚本过滤器 | Boolean | false |
hsts | 为 HTTP 严格传输安全(HSTS)策略设置选项。 | Object | - |
hsts.maxAge | HSTS 生效的秒数 | Integer | 31536000 |
hsts.includeSubDomains | 将 HSTS 应用于主机的所有子域名 | Boolean | true |
frameguard | 设置 X-Frame-Options 请求头以帮助缓解点击劫持攻击,设为 false 可禁用 | Boolean or Object | - |
frameguard.action | 值必须为 deny 或 sameorigin | String | sameorigin |
使用任何第三方上传提供方时,通常需要在此处设置自定义配置。请查看提供方文档了解需要哪些配置选项。
默认指令包含一个 market-assets.strapi.io 值。该值是为了应用内市场而设置的,保留它是安全的。
** 示例:用于使用 AWS-S3 提供方的 security 中间件自定义配置**
JavaScript
module.exports = [
// ...
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'yourBucketName.s3.yourRegion.amazonaws.com',
],
'media-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'yourBucketName.s3.yourRegion.amazonaws.com',
],
upgradeInsecureRequests: null,
},
},
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::security',
config: {
contentSecurityPolicy: {
useDefaults: true,
directives: {
'connect-src': ["'self'", 'https:'],
'img-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'yourBucketName.s3.yourRegion.amazonaws.com',
],
'media-src': [
"'self'",
'data:',
'blob:',
'market-assets.strapi.io',
'yourBucketName.s3.yourRegion.amazonaws.com',
],
upgradeInsecureRequests: null,
},
},
},
},
// ...
]
session
session 中间件允许使用基于 cookie 的会话,基于 koa-session。它接受以下选项:
| Option | Description | Type | Default value |
|---|---|---|---|
key | Cookie 键 | String | 'koa.sess' |
maxAge | Cookie 的最大生命周期,单位为毫秒。使用 'session' 会在会话关闭时使 cookie 过期。 | Integer or 'session' | 86400000 |
autoCommit | 自动提交请求头 | Boolean | true |
overwrite | 是否可以覆盖 | Boolean | true |
httpOnly | 是否为 httpOnly。使用 httpOnly 有助于缓解跨站脚本(XSS)攻击。 | Boolean | true |
signed | 对 cookie 进行签名 | Boolean | true |
rolling | 强制在每个响应上设置会话标识符 cookie。 | Boolean | false |
renew | 在会话即将过期时续期,使用户保持登录状态。 | Boolean | false |
secure | 强制使用 HTTPS | Boolean | true in production, false otherwise |
sameSite | 将 cookie 限制在first-party 或 same-site 上下文中 | String | null |
** 示例:session 中间件的自定义配置 **
JavaScript
module.exports = [
// ...
{
name: 'strapi::session',
config: {
rolling: true,
renew: true
},
},
// ...
]
TypeScript
export default [
// ...
{
name: 'strapi::session',
config: {
rolling: true,
renew: true
},
},
// ...
]