# 自定义错误处理

URL: https://caijiao.org/fastify/routing/error-handling
Source: docs/fastify/routing/error-handling.md
Description: 学习如何在 Fastify 中自定义错误处理逻辑，控制错误响应结构与日志输出。

[Fastify](/fastify/) 提供灵活的机制来自定义错误处理流程，包括全局错误钩子、Schema 校验错误格式化、以及手动抛出业务错误等。

## 全局错误处理钩子

使用 `setErrorHandler` 方法可以统一处理所有未捕获的错误：

```js
fastify.setErrorHandler((error, request, reply) => {
  request.log.error(error); // 打印日志
  reply.status(error.statusCode || 500).send({
    error: true,
    message: error.message
  });
});
```

该方法适用于：

- 请求处理函数中未捕获的异常
- Schema 校验失败
- 插件内部抛出的异常

## Schema 校验错误格式化

你可以通过 `setValidatorCompiler` 和 `setSchemaErrorFormatter` 来自定义校验器和错误格式：

```js
fastify.setSchemaErrorFormatter((errors, dataVar) => {
  return new Error(`校验失败：${errors[0].message}`);
});
```

默认情况下，Fastify 使用 AJV 生成详细的校验错误信息。

## 手动抛出 HTTP 错误

Fastify 提供 `fastify.httpErrors` 工具对象，可快速抛出带状态码的错误：

```js
fastify.get('/auth', async (request, reply) => {
  throw fastify.httpErrors.unauthorized('未登录或 Token 无效');
});
```

常见方法有：

- `badRequest()`
- `unauthorized()`
- `forbidden()`
- `notFound()`
- `internalServerError()`

## 局部错误处理（每个路由）

每个路由也可以设置独立的错误处理函数：

```js
fastify.get('/user', {
  handler: async () => {
    throw new Error('故意抛错');
  },
  errorHandler: (error, request, reply) => {
    reply.status(400).send({ msg: '自定义错误信息' });
  }
});
```

## 日志控制

可结合 `request.log` 输出结构化错误日志，方便排查：

```js
fastify.setErrorHandler((error, request, reply) => {
  request.log.warn({ err: error }, '请求出错');
  reply.status(500).send({ msg: '服务器内部错误' });
});
```
