错误处理
页面摘要: Strapi 的 API 以一致的结构返回错误,并允许后端代码为控制器、服务、策略或生命周期抛出自定义异常。本文档列出了错误类、上下文辅助函数,以及用于构建有意义响应的示例。
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的对象
JavaScript
// path: ./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);
}
}
// path: ./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();
}
TypeScript
// path: ./src/api/[api-name]/controllers/my-controller.ts
export default {
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);
}
}
// path: ./src/api/[api-name]/middlewares/my-middleware.ts
export default 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 方法执行自定义验证:
JavaScript
const { errors } = require('@strapi/utils');
const { ApplicationError } = errors;
const { createCoreService } = require('@strapi/strapi').factories;
module.exports = createCoreService('api::restaurant.restaurant', ({ strapi }) => ({
async create(params) {
let okay = false;
// 抛出错误将阻止餐厅被创建
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
const result = await super.create(params);
return result;
}
});
TypeScript
import { errors } from '@strapi/utils';
import { factories } from '@strapi/strapi';
const { ApplicationError } = errors;
export default factories.createCoreService('api::restaurant.restaurant', ({ strapi }) => ({
async create(params) {
let okay = false;
// 抛出错误将阻止餐厅被创建
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
const result = await super.create(params);
return result;
}
}));
示例:在模型生命周期中抛出错误**
此示例展示了构建一个 自定义模型生命周期,并能够抛出一个错误来停止请求,同时向管理面板返回正确的错误消息。通常你应该只在 beforeX 生命周期中抛出错误,而不是在 afterX 生命周期中。
JavaScript
const { errors } = require('@strapi/utils');
const { ApplicationError } = errors;
module.exports = {
beforeCreate(event) {
let okay = false;
// 抛出错误将阻止实体被创建
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
},
};
TypeScript
import { errors } from '@strapi/utils';
const { ApplicationError } = errors;
export default {
beforeCreate(event) {
let okay = false;
// 抛出错误将阻止实体被创建
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
},
};
策略
策略 是一种在控制器之前执行的特殊中间件。它们用于检查用户是否被允许执行该操作。如果用户不被允许执行该操作并且使用了 return false,则会抛出一个通用错误。作为替代方案,你可以使用从 Strapi ForbiddenError 类、ApplicationError 类(这两个类均参见 默认错误类)扩展的嵌套类,以及 Node Error 类,来抛出自定义错误消息。
PolicyError 类可从 @strapi/utils 包获取,接受 2 个参数:
- 函数的第一个参数是错误的
message(消息) - (可选)第二个参数是将被设置为响应中
details的对象;最佳实践是将policy键设置为抛出错误的策略名称。
示例:在自定义策略中抛出 PolicyError
此示例展示了构建一个 自定义策略,它将抛出自定义错误消息并停止请求。
JavaScript
const { errors } = require('@strapi/utils');
const { PolicyError } = errors;
module.exports = (policyContext, config, { strapi }) => {
let isAllowed = false;
if (isAllowed) {
return true;
} else {
throw new errors.PolicyError('You are not allowed to perform this action', {
policy: 'my-policy',
myCustomKey: 'myCustomValue',
});
}
}
TypeScript
import { errors } from '@strapi/utils';
const { PolicyError } = errors;
export default (policyContext, config, { strapi }) => {
let isAllowed = false;
if (isAllowed) {
return true;
} else {
throw new errors.PolicyError('You are not allowed to perform this action', {
policy: 'my-policy',
myCustomKey: 'myCustomValue',
});
}
};
默认错误类
默认错误类可从 @strapi/utils 包获取,并可在你的代码中导入和使用。任何默认错误类都可以被扩展以创建自定义错误类。然后该自定义错误类可用于在代码中抛出错误。
Application
ApplicationError 类是用于应用程序错误的通用错误类,通常推荐作为默认错误类。这个类专门设计用于抛出管理面板能够读取并展示给用户的适当错误消息。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | An application error occurred |
details | object | 用于定义附加详细信息的对象 | {} |
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
Pagination
PaginationError 类是一个特定错误类,通常在解析来自 REST、GraphQL 或 文档服务 的分页信息时使用。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Invalid pagination |
throw new errors.PaginationError('Exceeded maximum pageSize limit');
NotFound
NotFoundError 类是用于抛出 404 状态码错误的通用错误类。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Entity not found |
throw new errors.NotFoundError('These are not the droids you are looking for');
Forbidden
ForbiddenError 类是一个特定错误类,用于在用户未提供任何或正确的身份验证凭据时使用。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Forbidden access |
throw new errors.ForbiddenError('Ah ah ah, you didn\'t say the magic word');
传递给 ForbiddenError 的自定义 message 不会包含在 API 响应中。相反,API 返回默认消息。如果你需要返回指示权限不足的自定义错误消息,请改用 PolicyError。
Unauthorized
UnauthorizedError 类是一个特定错误类,用于在用户已正确通过身份验证、但没有执行特定操作的正确角色或权限时使用。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Unauthorized |
throw new errors.UnauthorizedError('You shall not pass!');
NotImplemented
NotImplementedError 类是一个特定错误类,用于传入的请求尝试使用当前未实现或未配置的功能时。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | This feature is not implemented yet |
throw new errors.NotImplementedError('This isn\'t implemented', { feature: 'test', implemented: false });
PayloadTooLarge
PayloadTooLargeError 类是一个特定错误类,用于传入的请求体或附加文件超出服务器限制时。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Entity too large |
throw new errors.PayloadTooLargeError('Uh oh, the file too big!');
Policy
PolicyError 类是一个特定错误,设计用于与 路由策略 一起使用。最佳实践建议确保策略名称在 details 参数中传递。它接受以下参数:
| 参数 | 类型 | 描述 | 默认值 |
|---|---|---|---|
message | string | 错误消息 | Policy Failed |
details | object | 用于定义附加详细信息的对象 | {} |
throw new errors.PolicyError('Something went wrong', { policy: 'my-policy' });
要在管理面板中处理 HTTP 错误(例如,在发起 API 请求的插件中),请使用 Strapi 内置 fetch 客户端的 isFetchError 工具和 FetchError 类。详情请参阅 管理面板 API:Fetch 客户端 > 错误处理。