Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update: pr#1801 #125

Merged
merged 1 commit into from
Aug 19, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
278 changes: 133 additions & 145 deletions docs/Hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,61 +4,40 @@

钩子 (hooks) 让你能够监听应用或请求/响应生命周期之上的特定事件。使用 `fastify.addHook` 可以注册钩子。你必须在事件被触发之前注册相应的钩子,否则,事件将得不到处理。

## 请求/响应钩子

通过钩子方法,你可以在 Fastify 的生命周期内直接进行交互。有五个可用的钩子 *(按执行顺序排序)*:
- `'onRequest'`
- `'preParsing'`
- `'preValidation'`
- `'preHandler'`
- `'preSerialization'`
- `'onError'`
- `'onSend'`
- `'onResponse'`

示例:
```js
fastify.addHook('onRequest', (request, reply, done) => {
// 其他代码
done()
})
通过钩子方法,你可以在 Fastify 的生命周期内直接进行交互。有七个可用的钩子 *(按执行顺序排序)*:

- [请求/响应钩子](#requestreply-hooks)
- [onRequest](#onRequest)
- [preParsing](#preParsing)
- [preValidation](#preValidation)
- [preHandler](#preHandler)
- [preSerialization](#preSerialization)
- [onError](#onError)
- [onSend](#onSend)
- [onResponse](#onResponse)
- [应用钩子](#application-hooks)
- [onClose](#onclose)
- [onRoute](#onroute)
- [onRegister](#onregister)

fastify.addHook('preParsing', (request, reply, done) => {
// 其他代码
done()
})

fastify.addHook('preValidation', (request, reply, done) => {
// 其他代码
done()
})

fastify.addHook('preHandler', (request, reply, done) => {
// 其他代码
done()
})
**注意**:使用 `async`/`await` 或返回一个 `Promise` 时,`done` 回调不可用。在这种情况下,仍然使用 `done` 可能会导致难以预料的行为,例如,处理函数的重复调用。

fastify.addHook('preSerialization', (request, reply, payload, done) => {
// 其他代码
done()
})
## 请求/响应钩子

fastify.addHook('onError', (request, reply, error, done) => {
// 其他代码
done()
})
[Request](https://github.com/fastify/docs-chinese/blob/master/docs/Request.md) 与 [Reply](https://github.com/fastify/docs-chinese/blob/master/docs/Reply.md) 是 Fastify 核心的对象。<br/>
`done` 是调用[生命周期](https://github.com/fastify/docs-chinese/blob/master/docs/Lifecycle.md)下一阶段的函数。

fastify.addHook('onSend', (request, reply, payload, done) => {
// 其他代码
done()
})
[生命周期](https://github.com/fastify/docs-chinese/blob/master/docs/Lifecycle.md)一文清晰地展示了各个钩子执行的位置。<br>
钩子可被封装,因此可以运用在特定的路由上。更多信息请看[作用域](#scope)一节。

fastify.addHook('onResponse', (request, reply, done) => {
### onRequest
```js
fastify.addHook('onRequest', (request, reply, done) => {
// 其他代码
done()
})
```
或使用 `async/await`
或使用 `async/await`
```js
fastify.addHook('onRequest', async (request, reply) => {
// 其他代码
Expand All @@ -69,28 +48,20 @@ fastify.addHook('onRequest', async (request, reply) => {
}
return
})
```

fastify.addHook('preParsing', async (request, reply) => {
// 其他代码
await asyncMethod()
// 发生错误
if (err) {
throw new Error('some errors occurred.')
}
return
})
**注意**:在 `onRequest` 钩子中,`request.body` 的值总是 `null`,这是因为 body 的解析发生在 `preHandler` 钩子之前。

fastify.addHook('preValidation', async (request, reply) => {
## preParsing
```js
fastify.addHook('preParsing', (request, reply, done) => {
// 其他代码
await asyncMethod()
// 发生错误
if (err) {
throw new Error('some errors occurred.')
}
return
done()
})

fastify.addHook('preHandler', async (request, reply) => {
```
或使用 `async/await`:
```js
fastify.addHook('preParsing', async (request, reply) => {
// 其他代码
await asyncMethod()
// 发生错误
Expand All @@ -99,23 +70,17 @@ fastify.addHook('preHandler', async (request, reply) => {
}
return
})

fastify.addHook('preSerialization', async (request, reply, payload) => {
```
### preValidation
```js
fastify.addHook('preValidation', (request, reply, done) => {
// 其他代码
await asyncMethod()
// 发生错误
if (err) {
throw new Error('some errors occurred.')
}
return payload
})

fastify.addHook('onError', async (request, reply, error) => {
// 当自定义错误日志时有用处
// 你不应该使用这个钩子去更新错误
done()
})

fastify.addHook('onSend', async (request, reply, payload) => {
```
或使用 `async/await`:
```js
fastify.addHook('preValidation', async (request, reply) => {
// 其他代码
await asyncMethod()
// 发生错误
Expand All @@ -124,8 +89,19 @@ fastify.addHook('onSend', async (request, reply, payload) => {
}
return
})
```
**注意**:在 `preValidation` 钩子中,`request.body` 的值总是 `null`,这是因为 body 的解析发生在 `preHandler` 钩子之前。

fastify.addHook('onResponse', async (request, reply) => {
### preHandler
```js
fastify.addHook('preHandler', (request, reply, done) => {
// 其他代码
done()
})
```
或使用 `async/await`:
```js
fastify.addHook('preHandler', async (request, reply) => {
// 其他代码
await asyncMethod()
// 发生错误
Expand All @@ -135,76 +111,46 @@ fastify.addHook('onResponse', async (request, reply) => {
return
})
```
### preSerialization

**注意**:使用 `async`/`await` 或返回一个 `Promise` 时,`done` 回调不可用。在这种情况下,仍然使用 `done` 可能会导致难以预料的行为,例如,处理函数的重复调用。

**注意**:在 `onRequest` 与 `preValidation` 钩子中,`request.body` 的值总是 `null`,这是因为 body 的解析发生在 `preHandler` 钩子之前。

[Request](https://github.com/fastify/docs-chinese/blob/master/docs/Request.md) 与 [Reply](https://github.com/fastify/docs-chinese/blob/master/docs/Reply.md) 是 Fastify 核心的对象。<br/>
`done` 是调用[生命周期](https://github.com/fastify/docs-chinese/blob/master/docs/Lifecycle.md)下一阶段的函数。

[生命周期](https://github.com/fastify/docs-chinese/blob/master/docs/Lifecycle.md)一文清晰地展示了各个钩子执行的位置。<br>
钩子可被封装,因此可以运用在特定的路由上。更多信息请看[作用域](#scope)一节。

在钩子的执行过程中如果发生了错误,只需将错误传递给 `done()`,Fastify 就会自动关闭请求,并发送一个相应的错误码给用户。
`preSerialization` 钩子让你可以在 payload 被序列化之前改动 (或替换) 它。举个例子:

```js
fastify.addHook('onRequest', (request, reply, done) => {
done(new Error('some error'))
fastify.addHook('preSerialization', (request, reply, payload, done) => {
var err = null;
var newPayload = { wrapped: payload }
done(err, newPayload)
})
```

如果你想自定义发送给用户的错误码,使用 `reply.code()` 即可:
或使用 `async/await`
```js
fastify.addHook('preHandler', (request, reply, done) => {
reply.code(400)
done(new Error('some error'))
fastify.addHook('preSerialization', async (request, reply, payload) => {
return {wrapped: payload }
})
```

*错误最终会在 [`Reply`](https://github.com/fastify/docs-chinese/blob/master/docs/Reply.md#errors) 中得到处理*

#### `onError` 钩子

`onError` 钩子可用于自定义错误日志,或当发生错误时添加特定的 header。<br/>
该钩子并不是为了变更错误而设计的,且调用 `reply.send` 会抛出一个异常。<br/>
它只会在 `customErrorHandler` 向用户发送错误之后被执行 (要注意的是,默认的 `customErrorHandler` 总是会发送错误)。
**注意**:与其他钩子不同,`onError` 不支持向 `done` 函数传递错误。
注:payload 为 `string`、`Buffer`、`stream` 或 `null` 时,该钩子不会被调用。

### onError
```js
fastify.addHook('onError', (request, reply, error, done) => {
// apm 代表应用性能监控 (Application Performance Monitoring)
apm.sendError(error)
// 其他代码
done()
})

// 或使用 async
fastify.addHook('onError', async (request, reply, error) => {
// apm 代表应用性能监控 (Application Performance Monitoring)
apm.sendError(error)
})
```

#### `preSerialization` 钩子

`preSerialization` 钩子让你可以在 payload 被序列化之前改动它。举个例子:

```js
fastify.addHook('preSerialization', (request, reply, payload, done) => {
var err = null;
var newPayload = { wrapped: payload }
done(err, newPayload)
})
// 或使用 async
fastify.addHook('preSerialization', async (request, reply, payload) => {
return { wrapped: payload }
或使用 `async/await`:
```js
fastify.addHook('onError', async (request, reply, error) => {
// 当自定义错误日志时有用处
// 你不应该使用这个钩子去更新错误
})
```
`onError` 钩子可用于自定义错误日志,或当发生错误时添加特定的 header。<br/>
该钩子并不是为了变更错误而设计的,且调用 `reply.send` 会抛出一个异常。<br/>
它只会在 `customErrorHandler` 向用户发送错误之后被执行 (要注意的是,默认的 `customErrorHandler` 总是会发送错误)。
**注意**:与其他钩子不同,`onError` 不支持向 `done` 函数传递错误。

payload 为 `string`、`Buffer`、`stream` 或 `null` 时,该钩子不会被调用。

#### `onSend` 钩子

### onSend
使用 `onSend` 钩子可以改变 payload。例如:

```js
Expand All @@ -213,8 +159,9 @@ fastify.addHook('onSend', (request, reply, payload, done) => {
var newPayload = payload.replace('some-text', 'some-new-text')
done(err, newPayload)
})

// 或者使用 async
```
或使用 `async/await`:
```js
fastify.addHook('onSend', async (request, reply, payload) => {
var newPayload = payload.replace('some-text', 'some-new-text')
return newPayload
Expand All @@ -235,9 +182,50 @@ fastify.addHook('onSend', (request, reply, payload, done) => {

注:你只能将 payload 修改为 `string`、`Buffer`、`stream` 或 `null`。

#### `onResponse` 钩子

### onResponse
```js

fastify.addHook('onResponse', (request, reply, done) => {
// 其他代码
done()
})
```
或使用 `async/await`:
```js
fastify.addHook('onResponse', async (request, reply) => {
// 其他代码
await asyncMethod()
// 发生错误
if (err) {
throw new Error('some errors occurred.')
}
return
})
```

当响应发出后,`onResponse` 钩子即被执行,因此在该钩子中你无法再向客户端发送数据了。但是你可以在此向外部服务发送数据,或是执行一些统计工作。

### 在钩子中管理错误
在钩子的执行过程中如果发生了错误,只需将错误传递给 `done()`,Fastify 就会自动关闭请求,并发送一个相应的错误码给用户。

```js
fastify.addHook('onRequest', (request, reply, done) => {
done(new Error('some error'))
})
```

如果你想自定义发送给用户的错误码,使用 `reply.code()` 即可:
```js
fastify.addHook('preHandler', (request, reply, done) => {
reply.code(400)
done(new Error('some error'))
})
```

*错误最终会在 [`Reply`](https://github.com/fastify/docs-chinese/blob/master/docs/Reply.md#errors) 中得到处理。*


### 在钩子中响应请求
需要的话,你可以在路由控制器执行前响应一个请求。一个例子便是身份验证的钩子。如果你在 `onRequest` 或 `preHandler` 中发出响应,请使用 `reply.send`。如果是在中间件中,使用 `res.end`。

Expand Down Expand Up @@ -265,12 +253,13 @@ fastify.addHook('onRequest', (request, reply, done) => {

你也可以在应用的生命周期里使用钩子方法。要格外注意的是,这些钩子并未被完全封装。钩子中的 `this` 得到了封装,但处理函数可以响应封装界线外的事件。

- `'onClose'`
- `'onRoute'`
- `'onRegister'`
- [onClose](#onclose)
- [onRoute](#onroute)
- [onRegister](#onregister)

<a name="on-close"></a>
**'onClose'**<br>

### onClose
使用 `fastify.close()` 停止服务器时被触发。当[插件](https://github.com/fastify/docs-chinese/blob/master/docs/Plugins.md)需要一个 "shutdown" 事件时有用,例如一个用于连接数据库的插件。<br>
该钩子的第一个参数是 Fastify 实例,第二个为 `done` 回调函数。
```js
Expand All @@ -280,8 +269,7 @@ fastify.addHook('onClose', (instance, done) => {
})
```
<a name="on-route"></a>
**'onRoute'**<br>

### onRoute
当注册一个新的路由时被触发。它的监听函数拥有一个唯一的参数:`routeOptions` 对象。该函数是同步的,其本身并不接受回调作为参数。
```js
fastify.addHook('onRoute', (routeOptions) => {
Expand All @@ -295,7 +283,7 @@ fastify.addHook('onRoute', (routeOptions) => {
})
```
<a name="on-register"></a>
**'onRegister'**<br>
### onRegister
当注册一个新的插件,或创建了新的封装好的上下文后被触发。该钩子在插件的代码**之前**被执行。<br/>
当你的插件需要知晓上下文何时创建完毕,并操作它们时,可以使用这一钩子。<br/>
**注意**:被 [`fastify-plugin`](https://github.com/fastify/fastify-plugin) 所封装的插件不会触发该钩子。
Expand Down Expand Up @@ -339,9 +327,9 @@ fastify.addHook('onRequest', function (request, reply, done) {

<a name="route-hooks"></a>
## 路由层钩子
你可以为**单个**路由声明一个或多个自定义的 `onRequest`、`preParsing`、`preHandler`、`preValidation``preSerialization` 钩子。
你可以为**单个**路由声明一个或多个自定义的 [onRequest](#onRequest)、[preParsing](#preParsing)、[preValidation](#preValidation)、[preHandler](#preHandler)[preSerialization](#preSerialization) 钩子。
如果你这么做,这些钩子总是会作为同一类钩子中的最后一个被执行。<br/>
当你需要进行认证时,这会很有用,而 `preParsing``preValidation` 钩子正是为此而生。
当你需要进行认证时,这会很有用,而 [preParsing](#preParsing)[preValidation](#preValidation) 钩子正是为此而生。
你也可以通过数组定义多个路由层钩子。

让我们看下范例:
Expand Down Expand Up @@ -408,4 +396,4 @@ fastify.route({
})
```

**注**:两个选项都接受一个函数数组作为参数。
**注**:两个选项都接受一个函数数组作为参数。