Version 3 and before of Fastify are no longer maintained.
For information about support options for end-of-life versions, see the Long Term Support page.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 Request 和 Reply 对象,而不是原生对象。
¥The logging Serializers have been updated to now
Fastify Request and
Reply objects instead of native ones.
如果任何自定义序列化器依赖于原生对象上存在的 request 或 reply 属性,但不存在于 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 (
setSchemaCompiler 和 setSchemaResolver 选项已被 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 开始,onRoute 和 onRegister 钩子的行为将略有变化以支持钩子封装。
¥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])(其中 req 是 IncomingMessage)仍然受支持,但已被弃用。
¥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
- 
无论钩子如何注册(#2005),它们现在都具有一致的上下文 ¥Hooks now have consistent context regardless of how they are registered (#2005) 
- 
已弃用 request.req和reply.res,用于request.raw和reply.raw(#2008)¥Deprecated request.reqandreply.resforrequest.rawandreply.raw(#2008)
- 
删除 modifyCoreObjects选项 (#2015)¥Removed modifyCoreObjectsoption (#2015)
- 
添加了 connectionTimeout选项 (#2086)¥Added connectionTimeoutoption (#2086)
- 
添加了 keepAliveTimeout选项 (#2086)¥Added keepAliveTimeoutoption (#2086)
- 
添加了将对象作为错误抛出的功能 (#2134) ¥Added the feature to throw object as error (#2134)