Skip to main content

响应

响应

¥Reply

介绍

¥Introduction

处理程序函数的第二个参数是 Reply。Reply 是 Fastify 的核心对象,它公开以下函数和属性:

¥The second parameter of the handler function is Reply. Reply is a core Fastify object that exposes the following functions and properties:

  • .code(statusCode) - 设置状态代码。

    ¥.code(statusCode) - Sets the status code.

  • .status(statusCode) - .code(statusCode) 的别名。

    ¥.status(statusCode) - An alias for .code(statusCode).

  • .statusCode - 阅读并设置 HTTP 状态代码。

    ¥.statusCode - Read and set the HTTP status code.

  • .elapsedTime - 返回自 Fastify 收到请求以来经过的时间。

    ¥.elapsedTime - Returns the amount of time passed since the request was received by Fastify.

  • .server - 对 fastify 实例对象的引用。

    ¥.server - A reference to the fastify instance object.

  • .header(name, value) - 设置响应标头。

    ¥.header(name, value) - Sets a response header.

  • .headers(object) - 将对象的所有键设置为响应标头。

    ¥.headers(object) - Sets all the keys of the object as response headers.

  • .getHeader(name) - 检索已设置的标头的值。

    ¥.getHeader(name) - Retrieve value of already set header.

  • .getHeaders() - 获取所有当前响应标头的浅拷贝。

    ¥.getHeaders() - Gets a shallow copy of all current response headers.

  • .removeHeader(key) - 删除先前设置的标头的值。

    ¥.removeHeader(key) - Remove the value of a previously set header.

  • .hasHeader(name) - 确定是否已设置标头。

    ¥.hasHeader(name) - Determine if a header has been set.

  • .writeEarlyHints(hints, callback) - 在准备响应时向用户发送早期提示。

    ¥.writeEarlyHints(hints, callback) - Sends early hints to the user while the response is being prepared.

  • .trailer(key, function) - 设置响应预告片。

    ¥.trailer(key, function) - Sets a response trailer.

  • .hasTrailer(key) - 确定是否已设置尾部。

    ¥.hasTrailer(key) - Determine if a trailer has been set.

  • .removeTrailer(key) - 删除先前设置的预告片的值。

    ¥.removeTrailer(key) - Remove the value of a previously set trailer.

  • .type(value) - 设置标头 Content-Type

    ¥.type(value) - Sets the header Content-Type.

  • .redirect(dest, [code,]) - 重定向到指定的 URL,状态代码是可选的(默认为 302)。

    ¥.redirect(dest, [code,]) - Redirect to the specified URL, the status code is optional (defaults to 302).

  • .callNotFound() - 调用自定义未找到处理程序。

    ¥.callNotFound() - Invokes the custom not found handler.

  • .serialize(payload) - 使用默认的 JSON 序列化器或使用自定义序列化器(如果已设置)序列化指定的有效负载并返回序列化的有效负载。

    ¥.serialize(payload) - Serializes the specified payload using the default JSON serializer or using the custom serializer (if one is set) and returns the serialized payload.

  • .getSerializationFunction(schema | httpStatus, [contentType]) - 如果设置了其中任何一个,则返回指定模式或 http 状态的序列化函数。

    ¥.getSerializationFunction(schema | httpStatus, [contentType]) - Returns the serialization function for the specified schema or http status, if any of either are set.

  • .compileSerializationSchema(schema, [httpStatus], [contentType]) - 使用默认(或自定义)SerializerCompiler 编译指定的模式并返回序列化函数。如果提供可选 httpStatus,则转发到 SerializerCompiler,默认为 undefined

    ¥.compileSerializationSchema(schema, [httpStatus], [contentType]) - Compiles the specified schema and returns a serialization function using the default (or customized) SerializerCompiler. The optional httpStatus is forwarded to the SerializerCompiler if provided, default to undefined.

  • .serializeInput(data, schema, [,httpStatus], [contentType]) - 使用指定的模式序列化指定的数据并返回序列化的有效负载。如果提供了可选的 httpStatuscontentType,则该函数将使用为该特定内容类型和 HTTP 状态代码提供的序列化器函数。默认为 undefined

    ¥.serializeInput(data, schema, [,httpStatus], [contentType]) - Serializes the specified data using the specified schema and returns the serialized payload. If the optional httpStatus, and contentType are provided, the function will use the serializer function given for that specific content type and HTTP Status Code. Default to undefined.

  • .serializer(function) - 为有效负载设置自定义序列化器。

    ¥.serializer(function) - Sets a custom serializer for the payload.

  • .send(payload) - 将有效负载发送给用户,可以是纯文本、缓冲区、JSON、流或错误对象。

    ¥.send(payload) - Sends the payload to the user, could be a plain text, a buffer, JSON, stream, or an Error object.

  • .sent - 如果你需要知道 send 是否已被调用,可以使用布尔值。

    ¥.sent - A boolean value that you can use if you need to know if send has already been called.

  • .hijack() - 中断正常请求生命周期。

    ¥.hijack() - interrupt the normal request lifecycle.

  • .raw - 来自 Node 核心的 http.ServerResponse

    ¥.raw - The http.ServerResponse from Node core.

  • .log - 传入请求的日志器实例。

    ¥.log - The logger instance of the incoming request.

  • .request - 传入请求。

    ¥.request - The incoming request.

fastify.get('/', options, function (request, reply) {
// Your code
reply
.code(200)
.header('Content-Type', 'application/json; charset=utf-8')
.send({ hello: 'world' })
})

.code(statusCode)

如果没有通过 reply.code 设置,则生成的 statusCode 将是 200

¥If not set via reply.code, the resulting statusCode will be 200.

.elapsedTime

调用自定义响应时间 getter 来计算自 Fastify 收到请求以来经过的时间。

¥Invokes the custom response time getter to calculate the amount of time passed since the request was received by Fastify.

const milliseconds = reply.elapsedTime

.statusCode

该属性读取并设置 HTTP 状态代码。当用作 setter 时,它是 reply.code() 的别名。

¥This property reads and sets the HTTP status code. It is an alias for reply.code() when used as a setter.

if (reply.statusCode >= 299) {
reply.statusCode = 500
}

.server

Fastify 服务器实例,作用域为当前 封装上下文

¥The Fastify server instance, scoped to the current encapsulation context.

fastify.decorate('util', function util () {
return 'foo'
})

fastify.get('/', async function (req, rep) {
return rep.server.util() // foo
})

.header(key, value)

设置响应标头。如果省略或未定义该值,则将其强制转换为 ''

¥Sets a response header. If the value is omitted or undefined, it is coerced to ''.

注意:标头的值必须使用 encodeURI 或类似模块(如 encodeurl)正确编码。无效字符将导致 500 TypeError 响应。

¥Note: the header's value must be properly encoded using encodeURI or similar modules such as encodeurl. Invalid characters will result in a 500 TypeError response.

有关更多信息,请参阅 http.ServerResponse#setHeader

¥For more information, see http.ServerResponse#setHeader.

    • 当以 set-cookie 为键将不同的值作为 cookie 发送时,每个值都将作为 cookie 发送,而不是替换以前的值。

      ¥When sending different values as a cookie with set-cookie as the key, every value will be sent as a cookie instead of replacing the previous value.

    reply.header('set-cookie', 'foo');
    reply.header('set-cookie', 'bar');
    • 浏览器将仅考虑 set-cookie 标头的键的最新引用。这样做是为了避免在添加到回复时解析 set-cookie 标头并加快回复的序列化速度。

      ¥The browser will only consider the latest reference of a key for the set-cookie header. This is done to avoid parsing the set-cookie header when added to a reply and speeds up the serialization of the reply.

    • 要重置 set-cookie 标头,你需要明确调用 reply.removeHeader('set-cookie'),请阅读有关 .removeHeader(key) 此处 的更多信息。

      ¥To reset the set-cookie header, you need to make an explicit call to reply.removeHeader('set-cookie'), read more about .removeHeader(key) here.

.headers(object)

将对象的所有键设置为响应标头。.header 将在后台调用。

¥Sets all the keys of the object as response headers. .header will be called under the hood.

reply.headers({
'x-foo': 'foo',
'x-bar': 'bar'
})

.getHeader(key)

检索先前设置的标头的值。

¥Retrieves the value of a previously set header.

reply.header('x-foo', 'foo') // setHeader: key, value
reply.getHeader('x-foo') // 'foo'

.getHeaders()

获取所有当前响应标头的浅拷贝,包括通过原始 http.ServerResponse 设置的响应标头。请注意,通过 Fastify 设置的标头优先于通过 http.ServerResponse 设置的标头。

¥Gets a shallow copy of all current response headers, including those set via the raw http.ServerResponse. Note that headers set via Fastify take precedence over those set via http.ServerResponse.

reply.header('x-foo', 'foo')
reply.header('x-bar', 'bar')
reply.raw.setHeader('x-foo', 'foo2')
reply.getHeaders() // { 'x-foo': 'foo', 'x-bar': 'bar' }

.removeHeader(key)

删除先前设置的标头的值。

¥Remove the value of a previously set header.

reply.header('x-foo', 'foo')
reply.removeHeader('x-foo')
reply.getHeader('x-foo') // undefined

.hasHeader(key)

返回一个布尔值,指示是否已设置指定的标头。

¥Returns a boolean indicating if the specified header has been set.

.writeEarlyHints(hints, callback)

向客户端发送早期提示。早期提示允许客户端在发送最终响应之前开始处理资源。这可以通过允许客户端在服务器仍在生成响应时预加载或预连接到资源来提高性能。

¥Sends early hints to the client. Early hints allow the client to start processing resources before the final response is sent. This can improve performance by allowing the client to preload or preconnect to resources while the server is still generating the response.

hints 参数是一个包含早期提示键值对的对象。

¥The hints parameter is an object containing the early hint key-value pairs.

示例:

¥Example:

reply.writeEarlyHints({
Link: '</styles.css>; rel=preload; as=style'
});

可选回调参数是一个函数,一旦发送提示或发生错误,该函数将被调用。

¥The optional callback parameter is a function that will be called once the hint is sent or if an error occurs.

.trailer(key, function)

设置响应预告片。通常在你需要在 data 之后发送需要大量资源的标头时使用尾部,例如 Server-TimingEtag。它可以保证客户端尽快收到响应数据。

¥Sets a response trailer. Trailer is usually used when you need a header that requires heavy resources to be sent after the data, for example, Server-Timing and Etag. It can ensure the client receives the response data as soon as possible.

注意:一旦你使用尾部,就会添加标头 Transfer-Encoding: chunked。这是在 Node.js 中使用预告片的硬性要求。

¥Note: The header Transfer-Encoding: chunked will be added once you use the trailer. It is a hard requirement for using trailer in Node.js.

注意:传递给 done 回调的任何错误都将被忽略。如果你对错误感兴趣,可以打开 debug 级别日志记录。

¥Note: Any error passed to done callback will be ignored. If you interested in the error, you can turn on debug level logging.

reply.trailer('server-timing', function() {
return 'db;dur=53, app;dur=47.2'
})

const { createHash } = require('node:crypto')
// trailer function also receive two argument
// @param {object} reply fastify reply
// @param {string|Buffer|null} payload payload that already sent, note that it will be null when stream is sent
// @param {function} done callback to set trailer value
reply.trailer('content-md5', function(reply, payload, done) {
const hash = createHash('md5')
hash.update(payload)
done(null, hash.disgest('hex'))
})

// when you prefer async-await
reply.trailer('content-md5', async function(reply, payload) {
const hash = createHash('md5')
hash.update(payload)
return hash.disgest('hex')
})

.hasTrailer(key)

返回一个布尔值,指示是否已设置指定的预告片。

¥Returns a boolean indicating if the specified trailer has been set.

.removeTrailer(key)

删除先前设置的预告片的值。

¥Remove the value of a previously set trailer.

reply.trailer('server-timing', function() {
return 'db;dur=53, app;dur=47.2'
})
reply.removeTrailer('server-timing')
reply.getTrailer('server-timing') // undefined

.redirect(dest, [code ,])

将请求重定向到指定的 URL,状态代码是可选的,默认为 302(如果尚未通过调用 code 设置状态代码)。

¥Redirects a request to the specified URL, the status code is optional, default to 302 (if status code is not already set by calling code).

注意:输入的 URL 必须使用 encodeURI 或类似模块(如 encodeurl)进行正确编码。无效的 URL 将导致 500 TypeError 响应。

¥Note: the input URL must be properly encoded using encodeURI or similar modules such as encodeurl. Invalid URLs will result in a 500 TypeError response.

示例(无 reply.code() 调用)将状态代码设置为 302 并重定向到 /home

¥Example (no reply.code() call) sets status code to 302 and redirects to /home

reply.redirect('/home')

示例(无 reply.code() 调用)将状态代码设置为 303 并重定向到 /home

¥Example (no reply.code() call) sets status code to 303 and redirects to /home

reply.redirect('/home', 303)

示例(reply.code() 调用)将状态代码设置为 303 并重定向到 /home

¥Example (reply.code() call) sets status code to 303 and redirects to /home

reply.code(303).redirect('/home')

示例(reply.code() 调用)将状态代码设置为 302 并重定向到 /home

¥Example (reply.code() call) sets status code to 302 and redirects to /home

reply.code(303).redirect('/home', 302)

.callNotFound()

调用自定义未找到处理程序。请注意,它只会调用 setNotFoundHandler 中指定的 preHandler 钩子。

¥Invokes the custom not found handler. Note that it will only call preHandler hook specified in setNotFoundHandler.

reply.callNotFound()

.type(contentType)

设置响应的内容类型。这是 reply.header('Content-Type', 'the/type') 的快捷方式。

¥Sets the content type for the response. This is a shortcut for reply.header('Content-Type', 'the/type').

reply.type('text/html')

如果 Content-Type 具有 JSON 子类型,并且未设置 charset 参数,则默认使用 utf-8 作为字符集。

¥If the Content-Type has a JSON subtype, and the charset parameter is not set, utf-8 will be used as the charset by default.

.getSerializationFunction(schema | httpStatus, [contentType])

通过使用提供的 schemahttpStatus 以及可选的 contentType 调用此函数,它将返回一个可用于序列化不同输入的 serialzation 函数。如果使用提供的输入中的任何一个都找不到序列化函数,则返回 undefined

¥By calling this function using a provided schema or httpStatus, and the optional contentType, it will return a serialzation function that can be used to serialize diverse inputs. It returns undefined if no serialization function was found using either of the provided inputs.

这在很大程度上取决于附加到路由的 schema#responses,或使用 compileSerializationSchema 编译的序列化函数。

¥This heavily depends of the schema#responses attached to the route, or the serialization functions compiled by using compileSerializationSchema.

const serialize = reply
.getSerializationFunction({
type: 'object',
properties: {
foo: {
type: 'string'
}
}
})
serialize({ foo: 'bar' }) // '{"foo":"bar"}'

// or

const serialize = reply
.getSerializationFunction(200)
serialize({ foo: 'bar' }) // '{"foo":"bar"}'

// or

const serialize = reply
.getSerializationFunction(200, 'application/json')
serialize({ foo: 'bar' }) // '{"foo":"bar"}'

请参阅 .compileSerializationSchema(schema, [httpStatus], [contentType]) 了解有关如何编译序列化模式的更多信息。

¥See .compileSerializationSchema(schema, [httpStatus], [contentType]) for more information on how to compile serialization schemas.

.compileSerializationSchema(schema, [httpStatus], [contentType])

该函数将编译序列化模式并返回可用于序列化数据的函数。返回的函数(又名序列化函数)是使用提供的 SerializerCompiler 编译的。此外,使用 WeakMap 可以缓存它以减少编译调用。

¥This function will compile a serialization schema and return a function that can be used to serialize data. The function returned (a.k.a. serialization function) returned is compiled by using the provided SerializerCompiler. Also this is cached by using a WeakMap for reducing compilation calls.

如果提供可选参数 httpStatuscontentType,则直接转发到 SerializerCompiler,因此如果使用自定义 SerializerCompiler,则可以使用它来编译序列化函数。

¥The optional parameters httpStatus and contentType, if provided, are forwarded directly to the SerializerCompiler, so it can be used to compile the serialization function if a custom SerializerCompiler is used.

这在很大程度上取决于附加到路由的 schema#responses,或使用 compileSerializationSchema 编译的序列化函数。

¥This heavily depends of the schema#responses attached to the route, or the serialization functions compiled by using compileSerializationSchema.

const serialize = reply
.compileSerializationSchema({
type: 'object',
properties: {
foo: {
type: 'string'
}
}
})
serialize({ foo: 'bar' }) // '{"foo":"bar"}'

// or

const serialize = reply
.compileSerializationSchema({
type: 'object',
properties: {
foo: {
type: 'string'
}
}
}, 200)
serialize({ foo: 'bar' }) // '{"foo":"bar"}'

// or

const serialize = reply
.compileSerializationSchema({
'3xx': {
content: {
'application/json': {
schema: {
name: { type: 'string' },
phone: { type: 'number' }
}
}
}
}
}, '3xx', 'application/json')
serialize({ name: 'Jone', phone: 201090909090 }) // '{"name":"Jone", "phone":201090909090}'

请注意,使用此函数时应小心,因为它将根据提供的架构缓存已编译的序列化函数。如果提供的模式发生修改或更改,则序列化函数将不会检测到模式已更改,例如,它将根据先前提供的模式的引用重用先前编译的序列化函数。

¥Note that you should be careful when using this function, as it will cache the compiled serialization functions based on the schema provided. If the schemas provided is mutated or changed, the serialization functions will not detect that the schema has been altered and for instance it will reuse the previously compiled serialization function based on the reference of the schema previously provided.

如果需要更改模式的属性,请始终选择创建一个全新的对象,否则实现将无法从缓存机制中受益。

¥If there's a need to change the properties of a schema, always opt to create a totally new object, otherwise the implementation won't benefit from the cache mechanism.

:使用以下模式作为示例:

¥:Using the following schema as example:

const schema1 = {
type: 'object',
properties: {
foo: {
type: 'string'
}
}
}

不是

¥Not

const serialize = reply.compileSerializationSchema(schema1)

// Later on...
schema1.properties.foo.type. = 'integer'
const newSerialize = reply.compileSerializationSchema(schema1)

console.log(newSerialize === serialize) // true

反而

¥Instead

const serialize = reply.compileSerializationSchema(schema1)

// Later on...
const newSchema = Object.assign({}, schema1)
newSchema.properties.foo.type = 'integer'

const newSerialize = reply.compileSerializationSchema(newSchema)

console.log(newSerialize === serialize) // false

.serializeInput(data, [schema | httpStatus], [httpStatus], [contentType])

此函数将根据提供的架构或 HTTP 状态代码序列化输入数据。如果同时提供,则 httpStatus 将优先。

¥This function will serialize the input data based on the provided schema or HTTP status code. If both are provided the httpStatus will take precedence.

如果给定的 schema 没有序列化函数,则将编译一个新的序列化函数,如果提供则转发 httpStatuscontentType

¥If there is not a serialization function for a given schema a new serialization function will be compiled, forwarding the httpStatus and contentType if provided.

reply
.serializeInput({ foo: 'bar'}, {
type: 'object',
properties: {
foo: {
type: 'string'
}
}
}) // '{"foo":"bar"}'

// or

reply
.serializeInput({ foo: 'bar'}, {
type: 'object',
properties: {
foo: {
type: 'string'
}
}
}, 200) // '{"foo":"bar"}'

// or

reply
.serializeInput({ foo: 'bar'}, 200) // '{"foo":"bar"}'

// or

reply
.serializeInput({ name: 'Jone', age: 18 }, '200', 'application/vnd.v1+json') // '{"name": "Jone", "age": 18}'

请参阅 .compileSerializationSchema(schema, [httpStatus], [contentType]) 了解有关如何编译序列化模式的更多信息。

¥See .compileSerializationSchema(schema, [httpStatus], [contentType]) for more information on how to compile serialization schemas.

.serializer(func)

默认情况下,.send() 将 JSON 序列化任何不属于 BufferstreamstringundefinedError 的值。如果你需要将默认序列化器替换为特定请求的自定义序列化器,则可以使用 .serializer() 实用程序执行此操作。请注意,如果你使用自定义序列化器,则必须设置自定义 'Content-Type' 标头。

¥By default, .send() will JSON-serialize any value that is not one of Buffer, stream, string, undefined, or Error. If you need to replace the default serializer with a custom serializer for a particular request, you can do so with the .serializer() utility. Be aware that if you are using a custom serializer, you must set a custom 'Content-Type' header.

reply
.header('Content-Type', 'application/x-protobuf')
.serializer(protoBuf.serialize)

请注意,你不需要在 handler 中使用此实用程序,因为缓冲区、流和字符串(除非设置了序列化程序)被视为已序列化。

¥Note that you don't need to use this utility inside a handler because Buffers, streams, and strings (unless a serializer is set) are considered to already be serialized.

reply
.header('Content-Type', 'application/x-protobuf')
.send(protoBuf.serialize(data))

有关发送不同类型值的更多信息,请参阅 .send()

¥See .send() for more information on sending different types of values.

.raw

这是来自 Node 核心的 http.ServerResponse。当你使用 Fastify Reply 对象时,使用 Reply.raw 函数的风险由你自行承担,因为你跳过了处理 HTTP 响应的所有 Fastify 逻辑。例如。:

¥This is the http.ServerResponse from Node core. Whilst you are using the Fastify Reply object, the use of Reply.raw functions is at your own risk as you are skipping all the Fastify logic of handling the HTTP response. e.g.:

app.get('/cookie-2', (req, reply) => {
reply.setCookie('session', 'value', { secure: false }) // this will not be used

// in this case we are using only the nodejs http server response object
reply.raw.writeHead(200, { 'Content-Type': 'text/plain' })
reply.raw.write('ok')
reply.raw.end()
})

响应 中解释了滥用 Reply.raw 的另一个例子。

¥Another example of the misuse of Reply.raw is explained in Reply.

.sent

顾名思义,.sent 是一个属性,用于指示是否已通过 reply.send() 发送响应。如果使用 reply.hijack(),它也将是 true

¥As the name suggests, .sent is a property to indicate if a response has been sent via reply.send(). It will also be true in case reply.hijack() was used.

如果路由处理程序被定义为异步函数或它返回 promise,则可以调用 reply.hijack() 来指示应跳过处理程序 promise 解析后自动调用 reply.send()。通过调用 reply.hijack(),应用对底层请求和响应承担全部责任。而且,钩子不会被调用。

¥In case a route handler is defined as an async function or it returns a promise, it is possible to call reply.hijack() to indicate that the automatic invocation of reply.send() once the handler promise resolve should be skipped. By calling reply.hijack(), an application claims full responsibility for the low-level request and response. Moreover, hooks will not be invoked.

直接修改 .sent 属性已被弃用。请使用上述 .hijack() 方法实现相同效果。

¥Modifying the .sent property directly is deprecated. Please use the aforementioned .hijack() method to achieve the same effect.

.hijack()

有时你可能需要停止正常请求生命周期的执行并手动发送响应。

¥Sometimes you might need to halt the execution of the normal request lifecycle and handle sending the response manually.

为了实现这一点,Fastify 提供了可以在请求生命周期内调用的 reply.hijack() 方法(在调用 reply.send() 之前的任何时间点),并允许你阻止 Fastify 发送响应,并阻止运行剩余的钩子(如果回复之前被劫持,则阻止用户处理程序)。

¥To achieve this, Fastify provides the reply.hijack() method that can be called during the request lifecycle (At any point before reply.send() is called), and allows you to prevent Fastify from sending the response, and from running the remaining hooks (and user handler if the reply was hijacked before).

app.get('/', (req, reply) => {
reply.hijack()
reply.raw.end('hello world')

return Promise.resolve('this will be skipped')
})

如果使用 reply.raw 将响应发送回用户,则仍将执行 onResponse 钩子。

¥If reply.raw is used to send a response back to the user, the onResponse hooks will still be executed.

.send(data)

顾名思义,.send() 是将有效负载发送给终端用户的函数。

¥As the name suggests, .send() is the function that sends the payload to the end user.

Objects

如上所述,如果你发送 JSON 对象,如果你设置了输出架构,send 将使用 fast-json-stringify 序列化对象,否则将使用 JSON.stringify()

¥As noted above, if you are sending JSON objects, send will serialize the object with fast-json-stringify if you set an output schema, otherwise, JSON.stringify() will be used.

fastify.get('/json', options, function (request, reply) {
reply.send({ hello: 'world' })
})

Strings

如果你将字符串传递给没有 Content-Typesend,它将作为 text/plain; charset=utf-8 发送。如果你设置了 Content-Type 标头并将字符串传递给 send,它将使用自定义序列化器进行序列化(如果已设置),否则,它将被不加修改地发送(除非 Content-Type 标头设置为 application/json; charset=utf-8,在这种情况下它将像对象一样进行 JSON 序列化 - 请参阅上面的部分)。

¥If you pass a string to send without a Content-Type, it will be sent as text/plain; charset=utf-8. If you set the Content-Type header and pass a string to send, it will be serialized with the custom serializer if one is set, otherwise, it will be sent unmodified (unless the Content-Type header is set to application/json; charset=utf-8, in which case it will be JSON-serialized like an object — see the section above).

fastify.get('/json', options, function (request, reply) {
reply.send('plain string')
})

Streams

如果你正在发送流并且你没有设置 'Content-Type' 标头,send 会将其设置为 'application/octet-stream'

¥If you are sending a stream and you have not set a 'Content-Type' header, send will set it to 'application/octet-stream'.

如上所述,流被认为是预序列化的,因此它们将在没有响应验证的情况下未经修改地发送。

¥As noted above, streams are considered to be pre-serialized, so they will be sent unmodified without response validation.

const fs = require('node:fs')

fastify.get('/streams', function (request, reply) {
const stream = fs.createReadStream('some-file', 'utf8')
reply.header('Content-Type', 'application/octet-stream')
reply.send(stream)
})

使用 async-await 时,你需要返回或等待响应对象:

¥When using async-await you will need to return or await the reply object:

const fs = require('node:fs')

fastify.get('/streams', async function (request, reply) {
const stream = fs.createReadStream('some-file', 'utf8')
reply.header('Content-Type', 'application/octet-stream')
return reply.send(stream)
})

Buffers

如果你正在发送缓冲区并且你没有设置 'Content-Type' 标头,send 会将其设置为 'application/octet-stream'

¥If you are sending a buffer and you have not set a 'Content-Type' header, send will set it to 'application/octet-stream'.

如上所述,缓冲区被认为是预序列化的,因此它们将在没有响应验证的情况下未经修改地发送。

¥As noted above, Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.

const fs = require('node:fs')

fastify.get('/streams', function (request, reply) {
fs.readFile('some-file', (err, fileBuffer) => {
reply.send(err || fileBuffer)
})
})

使用 async-await 时,你需要返回或等待响应对象:

¥When using async-await you will need to return or await the reply object:

const fs = require('node:fs')

fastify.get('/streams', async function (request, reply) {
fs.readFile('some-file', (err, fileBuffer) => {
reply.send(err || fileBuffer)
})
return reply
})

TypedArrays

send 像缓冲区一样管理 TypedArray,如果尚未设置,则将 'Content-Type' 标头设置为 'application/octet-stream'

¥send manages TypedArray like a Buffer, and sets the 'Content-Type' header to 'application/octet-stream' if not already set.

如上所述,TypedArray/Buffers 被认为是预序列化的,因此它们将在不进行响应验证的情况下未经修改地发送。

¥As noted above, TypedArray/Buffers are considered to be pre-serialized, so they will be sent unmodified without response validation.

const fs = require('node:fs')

fastify.get('/streams', function (request, reply) {
const typedArray = new Uint16Array(10)
reply.send(typedArray)
})

ReadableStream

ReadableStream 将被视为上面提到的节点流,内容被视为预序列化,因此它们将在未经修改的情况下发送,而无需响应验证。

¥ReadableStream will be treated as a node stream mentioned above, the content is considered to be pre-serialized, so they will be sent unmodified without response validation.

const fs = require('node:fs')
const { ReadableStream } = require('node:stream/web')

fastify.get('/streams', function (request, reply) {
const stream = fs.createReadStream('some-file')
reply.header('Content-Type', 'application/octet-stream')
reply.send(ReadableStream.from(stream))
})

响应

¥Response

Response 允许在一个地方管理回复负载、状态代码和标头。Response 中提供的有效负载被视为预序列化,因此它们将在未经修改的情况下发送,而无需进行响应验证。

¥Response allows to manage the reply payload, status code and headers in one place. The payload provided inside Response is considered to be pre-serialized, so they will be sent unmodified without response validation.

请注意,使用 Response 时,状态代码和标头不会直接反映到 reply.statusCodereply.getHeaders()。这种行为基于 Response 仅允许 readonly 状态代码和标头。数据不允许双向编辑,在检查 onSend 钩子中的 payload 时可能会造成混淆。

¥Please be aware when using Response, the status code and headers will not directly reflect to reply.statusCode and reply.getHeaders(). Such behavior is based on Response only allow readonly status code and headers. The data is not allow to be bi-direction editing, and may confuse when checking the payload in onSend hooks.

const fs = require('node:fs')
const { ReadableStream } = require('node:stream/web')

fastify.get('/streams', function (request, reply) {
const stream = fs.createReadStream('some-file')
const readableStream = ReadableStream.from(stream)
const response = new Response(readableStream, {
status: 200,
headers: { 'content-type': 'application/octet-stream' }
})
reply.send(response)
})

错误

¥Errors

如果你传递发送一个 Error 实例的对象,Fastify 将自动创建一个结构如下的错误:

¥If you pass to send an object that is an instance of Error, Fastify will automatically create an error structured as the following:

{
error: String // the HTTP error message
code: String // the Fastify error code
message: String // the user error message
statusCode: Number // the HTTP status code
}

你可以向 Error 对象添加自定义属性,例如 headers,这些属性将用于增强 HTTP 响应。

¥You can add custom properties to the Error object, such as headers, that will be used to enhance the HTTP response.

注意:如果你将错误传递给 send 并且 statusCode 小于 400,Fastify 会自动将其设置为 500。

¥Note: If you are passing an error to send and the statusCode is less than 400, Fastify will automatically set it at 500.

提示:你可以使用 http-errors 模块或 @fastify/sensible 插件生成错误来简化错误:

¥Tip: you can simplify errors by using the http-errors module or @fastify/sensible plugin to generate errors:

fastify.get('/', function (request, reply) {
reply.send(httpErrors.Gone())
})

要自定义 JSON 错误输出,你可以通过以下方式完成:

¥To customize the JSON error output you can do it by:

  • 为你需要的状态代码设置响应 JSON 模式

    ¥setting a response JSON schema for the status code you need

  • 将其他属性添加到 Error 实例

    ¥add the additional properties to the Error instance

请注意,如果返回的状态代码不在响应架构列表中,则将应用默认行为。

¥Notice that if the returned status code is not in the response schema list, the default behavior will be applied.

fastify.get('/', {
schema: {
response: {
501: {
type: 'object',
properties: {
statusCode: { type: 'number' },
code: { type: 'string' },
error: { type: 'string' },
message: { type: 'string' },
time: { type: 'string' }
}
}
}
}
}, function (request, reply) {
const error = new Error('This endpoint has not been implemented')
error.time = 'it will be implemented in two weeks'
reply.code(501).send(error)
})

如果你想自定义错误处理,请查看 setErrorHandler API。

¥If you want to customize error handling, check out setErrorHandler API.

注意:你在自定义错误处理程序时负责记录日志

¥Note: you are responsible for logging when customizing the error handler

应用编程接口:

¥API:

fastify.setErrorHandler(function (error, request, reply) {
request.log.warn(error)
const statusCode = error.statusCode >= 400 ? error.statusCode : 500
reply
.code(statusCode)
.type('text/plain')
.send(statusCode >= 500 ? 'Internal server error' : error.message)
})

请注意,在自定义错误处理程序中调用 reply.send(error) 会将错误发送到默认错误处理程序。查看 Reply 生命周期 以获取更多信息。

¥Beware that calling reply.send(error) in your custom error handler will send the error to the default error handler. Check out the Reply Lifecycle for more information.

路由生成的未找到错误将使用 setNotFoundHandler

¥The not found errors generated by the router will use the setNotFoundHandler

应用编程接口:

¥API:

fastify.setNotFoundHandler(function (request, reply) {
reply
.code(404)
.type('text/plain')
.send('a custom not found')
})

最终有效负载的类型

¥Type of the final payload

发送的有效负载的类型(在序列化并经过任何 onSend 钩子 之后)必须是以下类型之一,否则将引发错误:

¥The type of the sent payload (after serialization and going through any onSend hooks) must be one of the following types, otherwise, an error will be thrown:

  • string

  • Buffer

  • stream

  • undefined

  • null

异步等待和 Promise

¥Async-Await and Promises

Fastify 原生处理 Promise 并支持异步等待。

¥Fastify natively handles promises and supports async-await.

请注意,在以下示例中我们没有使用 reply.send。

¥Note that in the following examples we are not using reply.send.

const { promisify } = require('node:util')
const delay = promisify(setTimeout)

fastify.get('/promises', options, function (request, reply) {
return delay(200).then(() => { return { hello: 'world' }})
})

fastify.get('/async-await', options, async function (request, reply) {
await delay(200)
return { hello: 'world' }
})

被拒绝的 promise 默认为 500 HTTP 状态代码。使用具有 statusCode(或 status)和 message 属性的对象拒绝 promise 或 async function 中的 throw 以修改回复。

¥Rejected promises default to a 500 HTTP status code. Reject the promise, or throw in an async function, with an object that has statusCode (or status) and message properties to modify the reply.

fastify.get('/teapot', async function (request, reply) {
const err = new Error()
err.statusCode = 418
err.message = 'short and stout'
throw err
})

fastify.get('/botnet', async function (request, reply) {
throw { statusCode: 418, message: 'short and stout' }
// will return to the client the same json
})

如果你想了解更多信息,请查看 路由#async-await

¥If you want to know more please review Routes#async-await.

.then(fulfilled, rejected)

顾名思义,可以等待 Reply 对象,即 await reply 将等待直到发送回复。await 语法调用 reply.then()

¥As the name suggests, a Reply object can be awaited upon, i.e. await reply will wait until the reply is sent. The await syntax calls the reply.then().

reply.then(fulfilled, rejected) 接受两个参数:

¥reply.then(fulfilled, rejected) accepts two parameters:

  • 响应完全发送后,将调用 fulfilled

    ¥fulfilled will be called when a response has been fully sent,

  • 如果底层流出现错误,例如套接字已被破坏,将调用 rejected

    ¥rejected will be called if the underlying stream had an error, e.g. the socket has been destroyed.

有关更多详细信息,请参阅:

¥For more details, see: