错误处理 Error handling

借助 Strapi 的错误处理功能,您可以轻松地在应用程序中发送和接收错误。

Strapi 本身以标准格式处理错误。

错误处理有 2 个用例:

  • 作为通过 RESTGraphQL API 查询内容的开发人员,您可能会 接收错误 以响应请求。
  • 作为自定义 Strapi 应用程序后端的开发人员,您可以使用控制器和服务来 抛出错误

接收错误

错误包含在带有 error 键的响应对象中,并包含 HTTP 状态代码、错误名称和其他信息等信息。

REST 错误

REST API 抛出的错误包含在具有以下格式的 响应 中:

json
{
  "data": null,
  "error": {
    "status": "", // HTTP 状态
    "name": "", // Strapi 错误名称('ApplicationError' 或 'ValidationError')
    "message": "", // 人类可读的错误消息
    "details": {
      // 特定于错误类型的错误信息
    }
  }
}

GraphQL 错误

GraphQL API 抛出的错误包含在具有以下格式的 响应 中:

json
{
  "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.messageerror.details 属性:

  • 函数的第一个参数是错误 message
  • 第二个参数是将在收到的响应中设置为 details 的对象
js
JavaScript
js
// ./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方法进行自定义验证:

js
JavaScript
js
// ./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 生命周期中抛出错误。

js
JavaScript
js
// ./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

此示例显示如何构建 自定义策略,该策略将引发自定义错误消息并停止请求。

js
JavaScript
js
// ./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 类是应用程序错误的通用错误类,通常建议将其作为默认错误类。此类专门用于抛出管理面板可以读取并显示给用户的正确错误消息。它接受以下参数:

参数类型描述默认
messagestring错误消息应用程序发生错误
detailsobject用于定义其他详细信息的对象{}
js
throw new ApplicationError('Something went wrong', { foo: 'bar' })

分页

PaginationError 类是一个特定的错误类,通常在解析来自 RESTGraphQLEntity Service 的分页信息时使用。它接受以下参数:

参数类型描述默认
messagestring错误消息Invalid pagination
js
throw new PaginationError('Exceeded maximum pageSize limit')

NotFound

NotFoundError 类是一个通用的错误类,用于抛出 404 状态代码错误。它接受以下参数:

参数类型描述默认
messagestring错误消息未找到实体
js
throw new NotFoundError('这些不是您要查找的机器人')

Forbidden

ForbiddenError 类是一个特定的错误类(错误 403),当用户没有适当的角色或权限来执行特定操作但已正确验证时使用。它接受以下参数:

参数类型描述默认
messagestring错误消息禁止访问

注意:ForbiddenError 消息内容不会显示给 Content API,并将作为空的 ForbiddenError 返回给用户

js
throw new ForbiddenError('Ah ah ah, you didn\'t say the magic word')

Unauthorized

UnauthorizedError 类是一个特定的错误类(错误 401),当用户未提供任何或提供正确的身份验证凭据时使用。它接受以下参数:

参数类型说明默认
messagestring错误消息Unauthorized

注意:UnauthorizedError 消息内容不会显示给 Content API,并将作为空的 UnauthorizedError 返回给用户

js
throw new UnauthorizedError('You shall not pass!')

NotImplemented

NotImplementedError 类是一个特定的错误类,当传入请求试图使用当前未实现或配置的功能时使用。它接受以下参数:

参数类型说明默认
messagestring错误消息此功能未实现
js
throw new NotImplementedError('This isn\'t implement', { feature: 'test', implemented: false })

PayloadTooLarge

PayloadTooLargeError 类是当传入请求正文或附加文件超出服务器限制时使用的特定错误类。它接受以下参数:

参数类型说明默认
messagestring错误消息实体太大
js
throw new PayloadTooLargeError('哎呀,文件太大了!')

Policy

PolicyError 类是专门设计用于 路由策略 的特定错误。最佳实践建议是确保在 details 参数中传递策略的名称。它接受以下参数:

参数类型描述默认
messagestring错误消息Policy Failed
detailsobject用于定义其他详细信息的对象{}
js
throw new PolicyError('Something went wrong', { policy: 'my-policy' })

注意:由于 PolicyError 扩展了 ForbiddenError,它不会显示给 Content API,而是作为空的 ForbiddenError 返回给用户,如果您希望它在 Content API 中可见,则需要在策略中使用不同的错误类型。