中间件配置

页面摘要: /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',
    },
  },
];
TIP

如果你不确定将中间件放在栈中的什么位置,请将其添加到列表末尾。

命名约定

全局中间件可以根据其来源分为不同类型,这定义了以下命名约定:

Middleware typeOriginNaming 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 中创建的自定义中间件并配置)。 | -

由于它们直接从配置文件中配置和解析,因此没有命名约定。 |

可选配置

中间件可以有一个可选配置,包含以下参数:

ParameterDescriptionType
config用于定义或覆盖中间件配置Object
resolve中间件文件夹的路径(用于外部中间件很有用)String

内部中间件配置参考

Strapi 的核心包含以下内部中间件,主要用于性能、安全和错误处理:

MiddlewareAdded by DefaultRequired
bodyYesYes
compressionNoNo
corsYesYes
errorsYesYes
faviconYesYes
ipNoNo
loggerYesNo
poweredByYesNo
queryYesYes
response-timeNoNo
responsesYesYes
publicYesYes
securityYesYes
sessionYesNo

body

body 中间件基于 koa-body。它使用 node-formidable 库来处理文件。body 接受以下选项:

OptionDescriptionTypeDefault
multipart解析 multipart 请求体Booleantrue
patchKoa将请求体修补到 Koa 的 ctx.requestBooleantrue
jsonLimitJSON 请求体的字节限制(如果是整数)String or Integer1mb
formLimit表单请求体的字节限制(如果是整数)String or Integer56kb
textLimit文本请求体的字节限制(如果是整数)String or Integer56kb
encoding设置传入表单字段的编码Stringutf-8
formidable传递给 formidable multipart 解析器的选项(参见 node-formidable 文档)。Objectundefined

有关 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。它接受以下选项:

OptionDescriptionTypeDefault
threshold要压缩的最小响应大小(字节)String or Integer1kb
br切换 Brotli 压缩Booleantrue
gzip切换 gzip 压缩Booleanfalse
deflate切换 deflate 压缩Booleanfalse
defaultEncoding指定对没有 Accept-Encoding 请求头的请求使用哪些编码器Stringidentity

示例:compression 中间件的自定义配置

JavaScript


module.exports = [
  // ...
  {
    name: 'strapi::compression',
    config: {
      br: false
    },
  },
  // ...
]

TypeScript


export default [
  // ...
  {
    name: 'strapi::compression',
    config: {
      br: false
    },
  },
  // ...
]

cors

此安全中间件涉及跨源资源共享(CORS),基于 @koa/cors。它接受以下选项:

OptionDescriptionTypeDefault value
origin配置 Access-Control-Allow-Origin 请求头String or Array or Function'*'
maxAge配置 Access-Control-Max-Age 请求头,单位为秒String or Number31536000
credentials配置 Access-Control-Allow-Credentials 请求头Booleantrue
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.headerBooleanfalse

** 示例: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。它接受以下选项:

OptionDescriptionTypeDefault value
pathfavicon 文件的路径String'favicon.ico'
maxAgeCache-control max-age 指令,单位为毫秒Integer86400000

** 示例: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 过滤中间件。它接受以下选项:

OptionDescriptionTypeDefault value
whitelist白名单 IPArray[]
blacklist黑名单 IPArray[]
TIP

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 参数。它接受以下选项:

OptionDescriptionTypeDefault value
poweredByX-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 的查询解析器。它接受以下选项:

OptionDescriptionTypeDefault value
strictNullHandling区分 null 值和空字符串(参见 qs 文档)Booleantrue
arrayLimit解析数组时的最大索引限制(参见 qs 文档)Number100
depth解析对象时嵌套对象的最大深度(参见 qs 文档)Number20
NOTE

查询字符串中的方括号风格数组(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。它接受以下选项:

OptionDescriptionTypeDefault value
maxAgeCache-control max-age 指令,单位为毫秒Integer60000
NOTE

在 config 中使用驼峰命名的 maxAge 键,与表格一致。Strapi 5 只从你的 strapi::public 中间件 config 中读取此字段,并将其传递给 koa-static(参见 packages/core/core/src/middlewares/public.ts);defer 在核心中间件内部是固定的,因此你无需在此设置它。

TIP

你可以通过编辑服务器配置文件来自定义 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。它接受以下选项:

OptionDescriptionTypeDefault value
crossOriginEmbedderPolicy将 Cross-Origin-Embedder-Policy 请求头设为 require-corpBooleanfalse
crossOriginOpenerPolicy设置 Cross-Origin-Opener-Policy 请求头Booleanfalse
crossOriginResourcePolicy设置 Cross-Origin-Resource-Policy 请求头Booleanfalse
originAgentCluster设置 Origin-Agent-Cluster 请求头Booleanfalse
contentSecurityPolicy设置 Content-Security-Policy 请求头Object-
xssFilter通过将 X-XSS-Protection 请求头设为 0 来禁用浏览器的跨站脚本过滤器Booleanfalse
hsts为 HTTP 严格传输安全(HSTS)策略设置选项。Object-
hsts.maxAgeHSTS 生效的秒数Integer31536000
hsts.includeSubDomains将 HSTS 应用于主机的所有子域名Booleantrue
frameguard设置 X-Frame-Options 请求头以帮助缓解点击劫持攻击,设为 false 可禁用Boolean or Object-
frameguard.action值必须为 deny 或 sameoriginStringsameorigin
TIP

使用任何第三方上传提供方时,通常需要在此处设置自定义配置。请查看提供方文档了解需要哪些配置选项。

NOTE

默认指令包含一个 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。它接受以下选项:

OptionDescriptionTypeDefault value
keyCookie 键String'koa.sess'
maxAgeCookie 的最大生命周期,单位为毫秒。使用 'session' 会在会话关闭时使 cookie 过期。Integer or 'session'86400000
autoCommit自动提交请求头Booleantrue
overwrite是否可以覆盖Booleantrue
httpOnly是否为 httpOnly。使用 httpOnly 有助于缓解跨站脚本(XSS)攻击。Booleantrue
signed对 cookie 进行签名Booleantrue
rolling强制在每个响应上设置会话标识符 cookie。Booleanfalse
renew在会话即将过期时续期,使用户保持登录状态。Booleanfalse
secure强制使用 HTTPSBooleantrue in production, false otherwise
sameSite将 cookie 限制在first-party 或 same-site 上下文中Stringnull

** 示例:session 中间件的自定义配置 **

JavaScript


module.exports = [
  // ...
  {
    name: 'strapi::session',
    config: {
      rolling: true,
      renew: true
    },
  },
  // ...
]

TypeScript


export default [
  // ...
  {
    name: 'strapi::session',
    config: {
      rolling: true,
      renew: true
    },
  },
  // ...
]