Strapi 本身以标准格式处理错误。
错误处理有 2 个用例:
接收错误
错误包含在带有 error
键的响应对象中,并包含 HTTP 状态代码、错误名称和其他信息等信息。
REST 错误
REST API 抛出的错误包含在具有以下格式的 响应 中:
{
"data": null,
"error": {
"status": "", // HTTP 状态
"name": "", // Strapi 错误名称('ApplicationError' 或 'ValidationError')
"message": "", // 人类可读的错误消息
"details": {
// 特定于错误类型的错误信息
}
}
}
GraphQL 错误
GraphQL API 抛出的错误包含在具有以下格式的 响应 中:
{
"errors": [
{
"message": "", // 人性化的错误信息
"extensions": {
"error": {
"name": "", // Strapi 错误名称(“ApplicationError”或“ValidationError”),
"message": "", // 人性化的错误信息(与上文相同);
"details": {} // 特定于错误类型的错误信息
},
"code": "" // GraphQL 错误代码(例如:BAD_USER_INPUT)
}
}
],
"data": {
"graphQLQueryName": null
}
}
抛出错误
控制器和中间件
使用 Strapi 开发任何自定义逻辑时,抛出错误的推荐方法是让 控制器 或 中间件 以正确的状态和正文进行响应。
这可以通过在上下文(即 ctx
)上调用错误函数来实现。可用的错误函数列在 http-errors 文档 中,但它们的名称应采用小写驼峰格式,以便 Strapi 使用(例如 badRequest
)。
错误函数接受 2 个参数,它们对应于开发人员查询 API 时收到的 error.message
和 error.details
属性:
- 函数的第一个参数是错误
message
- 第二个参数是将在收到的响应中设置为
details
的对象
// ./src/api/[api-name]/controllers/my-controller.js
module.exports = {
renameDog: async (ctx, next) => {
const newName = ctx.request.body.name
if (!newName) {
return ctx.badRequest('name is missing', { foo: 'bar' })
}
ctx.body = strapi.service('api::dog.dog').rename(newName)
}
}
// ./src/api/[api-name]/middlewares/my-middleware.js
module.exports = async (ctx, next) => {
const newName = ctx.request.body.name
if (!newName) {
return ctx.badRequest('name is missing', { foo: 'bar' })
}
await next()
}
服务和模型生命周期
一旦您在比控制器或中间件更深的层上工作,就会有专用的错误类可用于抛出错误。这些类是 Node Error
类 的扩展,专门针对某些用例。
这些错误类通过 @strapi/utils
包导入,可以从多个不同的层调用。以下示例使用服务层,但错误类不仅限于服务和模型生命周期。在模型生命周期层中抛出错误时,建议使用 ApplicationError
类,以便在管理面板中显示正确的错误消息。
有关 Strapi 提供的错误类的更多信息,请参阅 默认错误类 部分。
示例:在服务中抛出错误
此示例显示包装核心服务并对create
方法进行自定义验证:
// ./src/api/restaurant/services/restaurant.js
const { errors } = require('@strapi/utils')
const { ApplicationError } = errors
const { createCoreService } = require('@strapi/strapi').factories
module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => ({
async create(params) {
const okay = false
// 抛出错误将阻止餐厅创建
if (!okay) {
throw new ApplicationError('Something went wrong', { foo: 'bar' })
}
const result = await super.create(params)
return result
}
}))
示例:在模型生命周期中抛出错误
此示例展示了如何构建 自定义模型生命周期,并能够抛出错误以停止请求并将正确的错误消息返回到管理面板。通常,您只应在 beforeX
生命周期中抛出错误,而不是在 afterX
生命周期中抛出错误。
// ./src/api/[api-name]/content-types/[api-name]/lifecycles.js
const { errors } = require('@strapi/utils')
const { ApplicationError } = errors
module.exports = {
beforeCreate(event) {
const okay = false
// 抛出错误将阻止创建实体
if (!okay) {
throw new ApplicationError('Something went wrong', { foo: 'bar' })
}
},
}
策略
策略 是一种特殊类型的中间件,在控制器之前执行。它们用于检查是否允许用户执行操作。如果不允许用户执行操作并使用 return false
,则会抛出一般错误。作为替代方案,您可以使用嵌套类扩展从 Strapi ForbiddenError
类、ApplicationError
类(请参阅 默认错误类 了解这两个类)以及最后的 Node Error
类 抛出自定义错误消息。
PolicyError
类可从 @strapi/utils
包中获得,并接受 2 个参数:
- 函数的第一个参数是错误
message
- (可选)第二个参数是将在收到的响应中设置为
details
的对象;最佳做法是使用引发错误的策略的名称设置“policy”键。
示例:在自定义策略中引发 PolicyError
此示例显示如何构建 自定义策略,该策略将引发自定义错误消息并停止请求。
// ./src/api/[api-name]/policies/my-policy.js
const { errors } = require('@strapi/utils')
const { PolicyError } = errors
module.exports = (policyContext, config, { strapi }) => {
const isAllowed = false
if (isAllowed) {
return true
}
else {
throw new PolicyError('You are not allowed to perform this action', {
policy: 'my-policy',
myCustomKey: 'myCustomValue',
})
}
}
默认错误类
默认错误类可从 @strapi/utils
包中获得,并且可以导入并在代码中使用。任何默认错误类都可以扩展以创建自定义错误类。然后可以在代码中使用自定义错误类来抛出错误。
应用程序
ApplicationError
类是应用程序错误的通用错误类,通常建议将其作为默认错误类。此类专门用于抛出管理面板可以读取并显示给用户的正确错误消息。它接受以下参数:
参数 | 类型 | 描述 | 默认 |
---|---|---|---|
message | string | 错误消息 | 应用程序发生错误 |
details | object | 用于定义其他详细信息的对象 | {} |
throw new ApplicationError('Something went wrong', { foo: 'bar' })
分页
PaginationError
类是一个特定的错误类,通常在解析来自 REST、GraphQL 或 Entity Service 的分页信息时使用。它接受以下参数:
参数 | 类型 | 描述 | 默认 |
---|---|---|---|
message | string | 错误消息 | Invalid pagination |
throw new PaginationError('Exceeded maximum pageSize limit')
NotFound
NotFoundError
类是一个通用的错误类,用于抛出 404
状态代码错误。它接受以下参数:
参数 | 类型 | 描述 | 默认 |
---|---|---|---|
message | string | 错误消息 | 未找到实体 |
throw new NotFoundError('这些不是您要查找的机器人')
Forbidden
ForbiddenError
类是一个特定的错误类(错误 403),当用户没有适当的角色或权限来执行特定操作但已正确验证时使用。它接受以下参数:
参数 | 类型 | 描述 | 默认 |
---|---|---|---|
message | string | 错误消息 | 禁止访问 |
注意:ForbiddenError
消息内容不会显示给 Content API,并将作为空的 ForbiddenError
返回给用户
throw new ForbiddenError('Ah ah ah, you didn\'t say the magic word')
Unauthorized
UnauthorizedError
类是一个特定的错误类(错误 401),当用户未提供任何或提供正确的身份验证凭据时使用。它接受以下参数:
参数 | 类型 | 说明 | 默认 |
---|---|---|---|
message | string | 错误消息 | Unauthorized |
注意:UnauthorizedError
消息内容不会显示给 Content API,并将作为空的 UnauthorizedError
返回给用户
throw new UnauthorizedError('You shall not pass!')
NotImplemented
NotImplementedError
类是一个特定的错误类,当传入请求试图使用当前未实现或配置的功能时使用。它接受以下参数:
参数 | 类型 | 说明 | 默认 |
---|---|---|---|
message | string | 错误消息 | 此功能未实现 |
throw new NotImplementedError('This isn\'t implement', { feature: 'test', implemented: false })
PayloadTooLarge
PayloadTooLargeError
类是当传入请求正文或附加文件超出服务器限制时使用的特定错误类。它接受以下参数:
参数 | 类型 | 说明 | 默认 |
---|---|---|---|
message | string | 错误消息 | 实体太大 |
throw new PayloadTooLargeError('哎呀,文件太大了!')
Policy
PolicyError
类是专门设计用于 路由策略 的特定错误。最佳实践建议是确保在 details
参数中传递策略的名称。它接受以下参数:
参数 | 类型 | 描述 | 默认 |
---|---|---|---|
message | string | 错误消息 | Policy Failed |
details | object | 用于定义其他详细信息的对象 | {} |
throw new PolicyError('Something went wrong', { policy: 'my-policy' })
注意:由于 PolicyError
扩展了 ForbiddenError
,它不会显示给 Content API,而是作为空的 ForbiddenError
返回给用户,如果您希望它在 Content API 中可见,则需要在策略中使用不同的错误类型。