Skip to main content

V3 迁移指南

¥V3 Migration Guide

本指南旨在帮助从 Fastify v2 迁移到 v3。

¥This guide is intended to help with migration from Fastify v2 to v3.

开始之前,请确保 v2 中的所有弃用警告均已修复。所有 v2 弃用内容均已删除,升级后它们将不再起作用。(#1750)

¥Before beginning please ensure that any deprecation warnings from v2 are fixed. All v2 deprecations have been removed and they will no longer work after upgrading. (#1750)

重大变更

¥Breaking changes

更改了中间件支持 ( #2014)

¥Changed middleware support (

从 Fastify v3 开始,框架本身就不再提供开箱即用的中间件支持。

¥From Fastify v3, middleware support does not come out-of-the-box with the framework itself.

如果你在应用中使用 Express 中间件,请在执行此操作之前安装并注册 @fastify/express@fastify/middie 插件。

¥If you use Express middleware in your application, please install and register the @fastify/express or @fastify/middie plugin before doing so.

v2:

// Using the Express `cors` middleware in Fastify v2.
fastify.use(require('cors')());

v3:

// Using the Express `cors` middleware in Fastify v3.
await fastify.register(require('@fastify/express'));
fastify.use(require('cors')());

更改了日志序列化 ( #2017)

¥Changed logging serialization (

日志记录 Serializers 已更新为现在的 Fastify RequestReply 对象,而不是原生对象。

¥The logging Serializers have been updated to now Fastify Request and Reply objects instead of native ones.

如果任何自定义序列化器依赖于原生对象上存在的 requestreply 属性,但不存在于 Fastify 对象上,则必须更新它们。

¥Any custom serializers must be updated if they rely upon request or reply properties that are present on the native objects but not the Fastify objects.

v2:

const fastify = require('fastify')({
logger: {
serializers: {
res(res) {
return {
statusCode: res.statusCode,
customProp: res.customProp
};
}
}
}
});

v3:

const fastify = require('fastify')({
logger: {
serializers: {
res(reply) {
return {
statusCode: reply.statusCode, // No change required
customProp: reply.raw.customProp // Log custom property from res object
};
}
}
}
});

更改了架构替换 ( #2023)

¥Changed schema substitution (

非标准 replace-way 共享架构支持已被删除。此功能已被符合 JSON 架构规范的基于 $ref 的替换所取代。为帮助理解此更改,请阅读 Fastify v3 中的验证和序列化

¥The non-standard replace-way shared schema support has been removed. This feature has been replaced with JSON Schema specification compliant $ref based substitution. To help understand this change read Validation and Serialization in Fastify v3.

v2:

const schema = {
body: 'schemaId#'
};
fastify.route({ method, url, schema, handler });

v3:

const schema = {
body: {
$ref: 'schemaId#'
}
};
fastify.route({ method, url, schema, handler });

更改了架构验证选项 ( #2023)

¥Changed schema validation options (

setSchemaCompilersetSchemaResolver 选项已被 setValidatorCompiler 取代,以实现未来的工具改进。为帮助理解此更改,请阅读 Fastify v3 中的验证和序列化

¥The setSchemaCompiler and setSchemaResolver options have been replaced with the setValidatorCompiler to enable future tooling improvements. To help understand this change read Validation and Serialization in Fastify v3.

v2:

const fastify = Fastify();
const ajv = new AJV();
ajv.addSchema(schemaA);
ajv.addSchema(schemaB);

fastify.setSchemaCompiler(schema => ajv.compile(schema));
fastify.setSchemaResolver(ref => ajv.getSchema(ref).schema);

v3:

const fastify = Fastify();
const ajv = new AJV();
ajv.addSchema(schemaA);
ajv.addSchema(schemaB);

fastify.setValidatorCompiler(({ schema, method, url, httpPart }) =>
ajv.compile(schema)
);

更改了 preParsing 钩子行为 ( #2286)

¥Changed preParsing hook behavior (

从 Fastify v3 开始,preParsing 钩子的行为将略有变化以支持请求负载操作。

¥From Fastify v3, the behavior of the preParsing hook will change slightly to support request payload manipulation.

钩子现在接受一个附加参数 payload,因此新的钩子签名是 fn(request, reply, payload, done)async fn(request, reply, payload)

¥The hook now takes an additional argument, payload, and therefore the new hook signature is fn(request, reply, payload, done) or async fn(request, reply, payload).

钩子可以选择通过 done(null, stream) 返回新流,或者在异步函数的情况下返回流。

¥The hook can optionally return a new stream via done(null, stream) or returning the stream in case of async functions.

如果钩子返回一个新流,则在后续钩子中将使用该新流代替原始流。一个示例用例是处理压缩请求。

¥If the hook returns a new stream, it will be used instead of the original one in subsequent hooks. A sample use case for this is handling compressed requests.

新流应将 receivedEncodedLength 属性添加到流中,该属性应反映从客户端收到的实际数据大小。例如,在压缩请求中,它应该是压缩有效负载的大小。此属性可以在 data 事件期间动态更新(并且应该)。

¥The new stream should add the receivedEncodedLength property to the stream that should reflect the actual data size received from the client. For instance, in a compressed request it should be the size of the compressed payload. This property can (and should) be dynamically updated during data events.

支持不带负载的 Fastify v2 旧语法,但已弃用。

¥The old syntax of Fastify v2 without payload is supported but it is deprecated.

更改了钩子行为 ( #2004)

¥Changed hooks behavior (

从 Fastify v3 开始,onRouteonRegister 钩子的行为将略有变化以支持钩子封装。

¥From Fastify v3, the behavior of onRoute and onRegister hooks will change slightly to support hook encapsulation.

  • onRoute - 钩子将被异步调用。现在,当在同一封装范围内注册新插件时,会继承该钩子。因此,应在注册任何插件之前注册此钩子。

    ¥onRoute - The hook will be called asynchronously. The hook is now inherited when registering a new plugin within the same encapsulation scope. Thus, this hook should be registered before registering any plugins.

  • onRegister - 与 onRoute 钩子相同。唯一的区别是,现在第一个调用将不再是框架本身,而是第一个注册的插件。

    ¥onRegister - Same as the onRoute hook. The only difference is that now the very first call will no longer be the framework itself, but the first registered plugin.

更改了内容类型解析器语法 ( #2286)

¥Changed Content Type Parser syntax (

在 Fastify v3 中,内容类型解析器现在具有解析器的单一签名。

¥In Fastify v3 the content type parsers now have a single signature for parsers.

新签名是 fn(request, payload, done)async fn(request, payload)。请注意,request 现在是 Fastify 请求,而不是 IncomingMessage。默认情况下,有效负载是一个流。如果在 addContentTypeParser 中使用了 parseAs 选项,则 payload 会反映选项值(字符串或缓冲区)。

¥The new signatures are fn(request, payload, done) or async fn(request, payload). Note that request is now a Fastify request, not an IncomingMessage. The payload is, by default, a stream. If the parseAs option is used in addContentTypeParser, then payload reflects the option value (string or buffer).

旧签名 fn(req, [done])fn(req, payload, [done])(其中 reqIncomingMessage)仍然受支持,但已被弃用。

¥The old signatures fn(req, [done]) or fn(req, payload, [done]) (where req is IncomingMessage) are still supported but are deprecated.

更改了 TypeScript 支持

¥Changed TypeScript support

Fastify 版本 3 中更改了类型系统。新的类型系统引入了通用约束和默认,以及定义模式类型(例如请求正文、查询字符串等)的新方法!

¥The type system was changed in Fastify version 3. The new type system introduces generic constraining and defaulting, plus a new way to define schema types such as a request body, querystring, and more!

v2:

interface PingQuerystring {
foo?: number;
}

interface PingParams {
bar?: string;
}

interface PingHeaders {
a?: string;
}

interface PingBody {
baz?: string;
}

server.get<PingQuerystring, PingParams, PingHeaders, PingBody>(
'/ping/:bar',
opts,
(request, reply) => {
console.log(request.query); // This is of type `PingQuerystring`
console.log(request.params); // This is of type `PingParams`
console.log(request.headers); // This is of type `PingHeaders`
console.log(request.body); // This is of type `PingBody`
}
);

v3:

server.get<{
Querystring: PingQuerystring;
Params: PingParams;
Headers: PingHeaders;
Body: PingBody;
}>('/ping/:bar', opts, async (request, reply) => {
console.log(request.query); // This is of type `PingQuerystring`
console.log(request.params); // This is of type `PingParams`
console.log(request.headers); // This is of type `PingHeaders`
console.log(request.body); // This is of type `PingBody`
});

管理未捕获的异常( #2073)

¥Manage uncaught exception (

在同步路由处理程序中,如果抛出错误,则服务器在设计上崩溃而不会调用配置的 .setErrorHandler()。这已经改变,现在同步和异步路由中的所有意外错误都得到了管理。

¥In sync route handlers, if an error was thrown the server crashed by design without calling the configured .setErrorHandler(). This has changed and now all unexpected errors in sync and async routes are managed.

v2:

fastify.setErrorHandler((error, request, reply) => {
// this is NOT called
reply.send(error)
})
fastify.get('/', (request, reply) => {
const maybeAnArray = request.body.something ? [] : 'I am a string'
maybeAnArray.substr() // Thrown: [].substr is not a function and crash the server
})

v3:

fastify.setErrorHandler((error, request, reply) => {
// this IS called
reply.send(error)
})
fastify.get('/', (request, reply) => {
const maybeAnArray = request.body.something ? [] : 'I am a string'
maybeAnArray.substr() // Thrown: [].substr is not a function, but it is handled
})

进一步的补充和改进

¥Further additions and improvements