错误处理
🌐 Error handling
Page summary:
Strapi 的 API 会以一致的结构返回错误,并允许后端代码为控制器、服务、策略或生命周期抛出自定义异常。本档文档列出了错误类、上下文助手以及编写有意义响应的示例。
Strapi 本身就以标准格式处理错误。
🌐 Strapi is natively handling errors with a standard format.
错误处理有 2 个用例:
🌐 There are 2 use cases for error handling:
收到错误
🌐 Receiving errors
错误包含在响应对象中,使用 error 键,并包括诸如 HTTP 状态码、错误名称及附加信息等信息。
🌐 Errors are included in the response object with the error key and include information such as the HTTP status code, the name of the error, and additional information.
REST 错误
🌐 REST errors
REST API 抛出的错误包含在具有以下格式的响应中:
🌐 Errors thrown by the REST API are included in the response that has the following format:
{
"data": null,
"error": {
"status": "", // HTTP status
"name": "", // Strapi error name ('ApplicationError' or 'ValidationError')
"message": "", // A human readable error message
"details": {
// error info specific to the error type
}
}
}
GraphQL 错误
🌐 GraphQL errors
GraphQL API 抛出的错误包含在具有以下格式的响应中:
🌐 Errors thrown by the GraphQL API are included in the response that has the following format:
{ "errors": [
{
"message": "", // A human reable error message
"extensions": {
"error": {
"name": "", // Strapi error name ('ApplicationError' or 'ValidationError'),
"message": "", // A human reable error message (same one as above);
"details": {}, // Error info specific to the error type
},
"code": "" // GraphQL error code (ex: BAD_USER_INPUT)
}
}
],
"data": {
"graphQLQueryName": null
}
}
抛出错误
🌐 Throwing errors
控制器和中间件
🌐 Controllers and middlewares
在使用 Strapi 开发任何自定义逻辑时,推荐的抛出错误的方式是让 controller 或 middleware 返回正确的状态和主体。
🌐 The recommended way to throw errors when developing any custom logic with Strapi is to have the controller or middleware respond with the correct status and body.
这可以通过在上下文上调用错误函数来完成(即 ctx)。可用的错误函数列在 http-errors documentation 中,但它们的名称在 Strapi 中使用时应该是小驼峰命名(例如 badRequest)。
错误函数接受两个参数,它们对应开发者在查询 API 时接收到的 error.message 和 error.details 属性 接收 :
🌐 Error functions accept 2 parameters that correspond to the error.message and error.details attributes received by a developer querying the API:
- 函数的第一个参数是错误
message - 第二个是将在收到的响应中被设置为
details的对象
- JavaScript
- TypeScript
// 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();
}
// 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();
}
服务和模型生命周期
🌐 Services and models lifecycles
一旦你在比控制器或中间件更深的层次工作,就有专门的错误类可以用来抛出错误。这些类是对 Node `Error` 类 的扩展,并且专门针对某些使用场景。
🌐 Once you are working at a deeper layer than the controllers or middlewares there are dedicated error classes that can be used to throw errors. These classes are extensions of Node `Error` class and are specifically targeted for certain use-cases.
这些错误类是通过 @strapi/utils 包导入的,可以从多个不同的层调用。以下示例使用服务层,但错误类不仅限于服务和模型生命周期。在模型生命周期层抛出错误时,建议使用 ApplicationError 类,以便在管理面板中显示适当的错误信息。
🌐 These error classes are imported through the @strapi/utils package and can be called from several different layers. The following examples use the service layer but error classes are not just limited to services and model lifecycles. When throwing errors in the model lifecycle layer, it's recommended to use the ApplicationError class so that proper error messages are shown in the admin panel.
请参阅 默认错误类 部分,以获取有关 Strapi 提供的错误类的更多信息。
🌐 See the default error classes section for more information on the error classes provided by Strapi.
示例:在服务中抛出错误**
🌐 Example: Throwing an error in a service**
此示例展示了如何封装一个 核心服务 并对 create 方法进行自定义验证:
🌐 This example shows wrapping a core service and doing a custom validation on the create method:
- JavaScript
- TypeScript
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;
// Throwing an error will prevent the restaurant from being created
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
const result = await super.create(params);
return result;
}
});
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;
// Throwing an error will prevent the restaurant from being created
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
const result = await super.create(params);
return result;
}
}));
示例:在模型生命周期中抛出错误**
🌐 Example: Throwing an error in a model lifecycle**
此示例展示了如何构建一个自定义模型生命周期并能够抛出一个错误,该错误会停止请求并将适当的错误信息返回给管理面板。通常你应该只在 beforeX 生命周期中抛出错误,而不是在 afterX 生命周期中抛出。
🌐 This example shows building a custom model lifecycle and being able to throw an error that stops the request and will return proper error messages to the admin panel. Generally you should only throw an error in beforeX lifecycles, not afterX lifecycles.
- JavaScript
- TypeScript
const { errors } = require('@strapi/utils');
const { ApplicationError } = errors;
module.exports = {
beforeCreate(event) {
let okay = false;
// Throwing an error will prevent the entity from being created
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
},
};
import { errors } from '@strapi/utils';
const { ApplicationError } = errors;
export default {
beforeCreate(event) {
let okay = false;
// Throwing an error will prevent the entity from being created
if (!okay) {
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
}
},
};
政策
🌐 Policies
策略 是一种特殊类型的中间件,在控制器执行之前运行。它们用于检查用户是否被允许执行该操作。如果用户不被允许执行该操作并且使用了 return false,则会抛出通用错误。作为替代,你可以使用从 Strapi ForbiddenError 类、ApplicationError 类派生的嵌套类扩展来抛出自定义错误消息(请参阅 默认错误类 了解这两个类),最后还可以使用 Node `Error` 类。
PolicyError 类可从 @strapi/utils 包中获得,并接受 2 个参数:
🌐 The PolicyError class is available from @strapi/utils package and accepts 2 parameters:
- 函数的第一个参数是错误
message - (可选) 第二个参数是将被设置为响应中
details的对象;一个最佳做法是设置一个policy键,其值为抛出错误的策略名称。
示例:在自定义策略中抛出 PolicyError
🌐 Example: Throwing a PolicyError in a custom policy
此示例展示了如何构建一个 自定义策略,该策略将抛出自定义错误消息并停止请求。
🌐 This example shows building a custom policy that will throw a custom error message and stop the request.
- JavaScript
- TypeScript
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',
});
}
}
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',
});
}
};
默认错误类
🌐 Default error classes
默认的错误类可以从 @strapi/utils 包中获得,并可以在你的代码中导入和使用。任何默认的错误类都可以被扩展以创建自定义错误类。然后,自定义错误类可以在你的代码中使用来抛出错误。
🌐 The default error classes are available from the @strapi/utils package and can be imported and used in your code. Any of the default error classes can be extended to create a custom error class. The custom error class can then be used in your code to throw errors.
- Application
- Pagination
- NotFound
- Forbidden
- Unauthorized
- NotImplemented
- PayloadTooLarge
- Policy
ApplicationError 类是一个通用的应用错误类,通常推荐作为默认的错误类。该类专门设计用于抛出管理员面板可以读取并显示给用户的正确错误信息。它接受以下参数:
🌐 The ApplicationError class is a generic error class for application errors and is generally recommended as the default error class. This class is specifically designed to throw proper error messages that the admin panel can read and show to the user. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | An application error occured || details | object | 定义额外细节的对象 | {} |
throw new errors.ApplicationError('Something went wrong', { foo: 'bar' });
PaginationError 类是一个特定的错误类,通常用于解析来自 REST、GraphQL 或 Document Service 的分页信息。它接受以下参数:
🌐 The PaginationError class is a specific error class that is typically used when parsing the pagination information from REST, GraphQL, or the Document Service. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Invalid pagination |
throw new errors.PaginationError('Exceeded maximum pageSize limit');
NotFoundError 类是一个通用错误类,用于抛出 404 状态码错误。它接受以下参数:
🌐 The NotFoundError class is a generic error class for throwing 404 status code errors. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Entity not found |
throw new errors.NotFoundError('These are not the droids you are looking for');
ForbiddenError 类是一个特定的错误类,当用户未提供任何或正确的认证凭据时使用。它接受以下参数:
🌐 The ForbiddenError class is a specific error class used when a user either doesn't provide any or the correct authentication credentials. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Forbidden access |
throw new errors.ForbiddenError('Ah ah ah, you didn\'t say the magic word');
UnauthorizedError 类是一个特定的错误类,用于当用户没有执行特定操作的适当角色或权限,但已经正确认证时。它接受以下参数:
🌐 The UnauthorizedError class is a specific error class used when a user doesn't have the proper role or permissions to perform a specific action, but has properly authenticated. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Unauthorized |
throw new errors.UnauthorizedError('You shall not pass!');
NotImplementedError 类是一个特定的错误类,当传入请求试图使用当前未实现或未配置的功能时使用。它接受以下参数:
🌐 The NotImplementedError class is a specific error class used when the incoming request is attempting to use a feature that is not currently implemented or configured. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | This feature isn't implemented |
throw new errors.NotImplementedError('This isn\'t implemented', { feature: 'test', implemented: false });
PayloadTooLargeError 类是一个特定的错误类,用于当传入的请求主体或附加文件超过服务器限制时使用。它接受以下参数:
🌐 The PayloadTooLargeError class is a specific error class used when the incoming request body or attached files exceed the limits of the server. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Entity too large |
throw new errors.PayloadTooLargeError('Uh oh, the file too big!');
PolicyError 类是一个特定的错误,设计用于与 路由策略 一起使用。最佳实践建议是确保在 details 参数中传入策略名称。它接受以下参数:
🌐 The PolicyError class is a specific error designed to be used with route policies. The best practice recommendation is to ensure the name of the policy is passed in the details parameter. It accepts the following parameters:
| 参数 | 类型 | 描述 | 默认值 || --- | --- | --- | --- || message | string | 错误信息 | Policy Failed || details | object | 定义额外细节的对象 | {} |
throw new errors.PolicyError('Something went wrong', { policy: 'my-policy' });