Deep Dive into Fastify: Das hochleistungsfähige Node.js Web-Framework
Olivia Novak
Dev Intern · Leapcell

Fastify: Ein hochleistungsfähiges Node.js Web-Framework
Fastify ist ein effizientes und schnelles Node.js Web-Framework, das auf optimale Leistung ausgelegt ist. Obwohl es relativ neu ist, hat es aufgrund seiner hohen Leistung und des geringen Overheads die Gunst vieler Entwickler gewonnen. Fastify bietet eine prägnante Entwicklungserfahrung, unterstützt schnelles Routing und eine Plugin-Architektur, wodurch es Entwicklern erleichtert wird, Anwendungen zu erstellen und zu erweitern. Unter Bezugnahme auf die Fastify offizielle Website wird im Folgenden Fastify aus verschiedenen Perspektiven vorgestellt.
1. Hauptmerkmale und -prinzipien
- Hohe Leistung: Fastify ist eines der schnellsten Web-Frameworks. Abhängig von der Codekomplexität kann es bis zu 30.000 Anfragen pro Sekunde verarbeiten.
- Skalierbarkeit: Mithilfe von Hooks, Plugins und Decorators ist Fastify vollständig skalierbar.
- Schema-basiert: Obwohl nicht obligatorisch, wird empfohlen, JSON Schema zur Validierung von Routen und zur Serialisierung von Ausgaben zu verwenden. Fastify kompiliert das Schema in hochleistungsfähige Funktionen.
- Logging: Die Wahl des besten Loggers Pino eliminiert fast die Kosten für das Logging.
- Entwicklerfreundlich: Dieses Framework ist sehr ausdrucksstark und bequem für den täglichen Gebrauch der Entwickler, ohne die Leistung und Sicherheit zu beeinträchtigen.
- TypeScript-Ready: Es ist bestrebt, TypeScript-Typdeklarationsdateien zu pflegen, um die wachsende TypeScript-Community zu unterstützen.
2. Hintergrund seiner Entstehung
Bevor Fastify aufkam, waren Express und Koa zwei weit verbreitete Frameworks im Node.js-Bereich. Obwohl sie beliebt und einfach zu bedienen sind, ist ihre Leistung bei der Verarbeitung einer großen Anzahl von Anfragen nicht optimal. Fastify zielt darauf ab, die folgenden Hauptprobleme zu lösen:
- Leistung: Durch die Reduzierung des Overheads jeder Anfrage bietet es eine höhere Leistung als bestehende Frameworks und kann mehr Anfragen verarbeiten, was für die Erstellung von Hochleistungsanwendungen entscheidend ist.
- Entwicklungseffizienz: Mithilfe der Plugin-Architektur und sofort einsatzbereiter Funktionen (wie Schema-Validierung, Logging usw.) bietet es eine effiziente und einfach zu bedienende Entwicklungsumgebung, die den Entwicklungsprozess beschleunigt und potenzielle Fehler reduziert.
- Schema-Validierung: Es verfügt über eine integrierte Unterstützung für JSON Schema, die nicht nur bei der Validierung von Client-Eingaben hilft, sondern auch die Datenkonsistenz und Zuverlässigkeit der Anwendung gewährleistet. Dies ist eine Funktion, die viele Frameworks nicht auf Kernebene integrieren.
- Skalierbarkeit: Die Plugin-Architektur ermöglicht es Entwicklern, auf einfache Weise neue Funktionen hinzuzufügen oder Bibliotheken von Drittanbietern zu integrieren, ohne die Gesamtleistung der Anwendung wesentlich zu beeinträchtigen.
Durch die Lösung der oben genannten Probleme bietet Fastify eine leistungsstarke Plattform für die Entwicklung von hochleistungsfähigen, wartungsfreundlichen und einfach zu entwickelnden Node.js-Anwendungen und hat in der JavaScript-Community schnell Aufmerksamkeit und Verwendung gefunden.
3. Realisierung hoher Leistung
Der Schlüssel zu Fastifys hoher Leistung liegt in seinem Design und seinen architektonischen Entscheidungen, die dazu beitragen, den Overhead jeder Anfrage zu minimieren:
- Effiziente Routing-Verteilung: Fastify verwendet einen schnellen Routing-Verteilungsmechanismus. Wenn eine Anfrage eingeht, kann es schnell die zu aufrufende Verarbeitungsfunktion ermitteln, wodurch die Anfrageverarbeitungszeit erheblich reduziert wird.
- Vorkompilierte Serialisierung: Vor dem Senden einer Antwort verwendet Fastify vorkompilierte Serialisierungsfunktionen anstelle der dynamischen Serialisierung von Objekten zur Laufzeit, wodurch die Serialisierung von Antworten beschleunigt und an Clients gesendet wird.
- Schema-gesteuerte Entwicklung: Fastify empfiehlt dringend (und erfordert in einigen Fällen) die Verwendung von JSON Schema zur Definition der Ein- und Ausgabe von Routen. Dies hilft nicht nur bei der Validierung und Dokumentation der API, sondern ermöglicht es Fastify auch, die Validierungslogik vorkompilieren und so die Laufzeiteffizienz zu verbessern.
- Optimiertes Plugin-System: Die Plugin-Architektur von Fastify ist effizient konzipiert und unterstützt die Wiederverwendung von Code und Best Practices, während das Core-Framework schlank gehalten wird, wodurch ein hoher Grad an Modularität und Flexibilität erreicht wird, ohne die Leistung zu beeinträchtigen.
- Effizientes Logging: Das integrierte Logging-Tool Pino ist auf Geschwindigkeit ausgelegt und bietet Logging-Funktionen mit extrem geringem Overhead, was für die Aufrechterhaltung der Anwendungsleistung entscheidend ist.
- Null-Kosten-Abstraktion: Die Designphilosophie von Fastify besteht darin, den Leistungs-Overhead der Abstraktionsschicht zu minimieren. Selbst bei Verwendung verschiedener Abstraktionen und komfortabler Funktionen kann es eine hohe Leistung aufrechterhalten.
Durch diese Designentscheidungen und Optimierungen kann Fastify eine hervorragende Leistung bieten und ist eine ideale Wahl für die Erstellung effizienter und reaktionsschneller Node.js-Anwendungen.
4. Installation und Nutzung
4.1 Installieren Sie Fastify über npm
npm install fastify
4.2 Einfaches Beispielcode
// Importieren Sie das Framework und instanziieren Sie es import Fastify from "fastify"; const fastify = Fastify({ logger: true, }); // Deklarieren Sie eine Route fastify.get("/", async function handler(request, reply) { return { hello: "world" }; }); // Führen Sie den Server aus! try { await fastify.listen({ port: 3000 }); } catch (err) { fastify.log.error(err); process.exit(1); }
4.3 Generieren Sie ein Skeleton mit der CLI
npm install --global fastify-cli fastify generate newproject
4.4 Beispiel für die Bearbeitung von Anfragen mit JSON-Schema und Hooks
import Fastify from "fastify"; const fastify = Fastify({ logger: true, }); fastify.route({ method: "GET", url: "/", schema: { // Die Anfrage muss eine Abfragezeichenfolge mit einem `name`-Parameter haben querystring: { type: "object", properties: { name: { type: "string" }, }, required: ["name"], }, // Die Antwort muss ein Objekt mit einer `hello`-Eigenschaft vom Typ 'string' sein response: { 200: { type: "object", properties: { hello: { type: "string" }, }, }, }, }, // Diese Funktion wird für jede Anfrage ausgeführt, bevor der Handler ausgeführt wird preHandler: async (request, reply) => { // Z.B. Authentifizierung prüfen }, handler: async (request, reply) => { return { hello: "world" }; }, }); try { await fastify.listen({ port: 3000 }); } catch (err) { fastify.log.error(err); process.exit(1); }
5. Plugins, Dekoratoren, Middleware, Hooks
In Fastify sind Plugins, Dekoratoren, Middleware und Hooks Kernkonzepte des Frameworks, die jeweils eine unterschiedliche Rolle spielen:
5.1 Plugins
Plugins sind die wichtigste Möglichkeit, Funktionen hinzuzufügen, Code freizugeben oder Logik in einer Fastify-Anwendung zu kapseln. Ein Plugin kann eine Funktion sein, die eine Fastify-Instanz, Optionen und eine Callback-Funktion als Parameter entgegennimmt. Plugins können Routen registrieren, Dekoratoren hinzufügen, neue Hooks deklarieren und sogar andere Plugins kapseln und werden zum Erstellen modularer Anwendungen verwendet. Entwickler können sie verwenden, um wiederverwendbare Logikblöcke zu erstellen und in verschiedenen Fastify-Anwendungen oder verschiedenen Teilen derselben Anwendung freizugeben.
5.2 Dekoratoren
Dekoratoren werden verwendet, um die Fastify-Instanz, Request- und Reply-Objekte zu erweitern. Durch das Hinzufügen neuer Methoden oder Eigenschaften können Entwickler benutzerdefinierte Funktionen oder Daten hinzufügen und in verschiedenen Teilen der Anwendung verfügbar machen. Beispielsweise kann ein Dekorator hinzugefügt werden, um eine Methode zum Zugriff auf freigegebene Konfigurationsdaten oder Dienste für jede Anfrage hinzuzufügen.
5.3 Middleware
Obwohl Fastify nicht dafür ausgelegt ist, sich auf Middleware zu verlassen, unterstützt es die Verwendung von Express/Connect-Style-Middleware, hauptsächlich zur Kompatibilität oder Integration spezifischer Funktionen. Middleware kann auf die Request- und Response-Objekte zugreifen, Code ausführen, die Request- und Response-Objekte ändern, die Request-Verarbeitungskette beenden oder die nächste Middleware im Call Stack aufrufen. Bei Verwendung von Fastify-Middleware ist Vorsicht geboten, da eine unsachgemäße Verwendung einige Optimierungen von Fastify umgehen und die Leistung beeinträchtigen kann.
5.4 Hooks
Hooks sind ein Mechanismus in Fastify, der es Entwicklern ermöglicht, in verschiedenen Phasen des Request-Lebenszyklus einzugreifen und Logik auszuführen (z. B. nachdem die Anfrage empfangen wurde, bevor die Route aufgelöst wird, bevor die Antwort gesendet wird usw.). Hooks können verwendet werden, um Vor- oder Nachbearbeitungslogik auszuführen, z. B. Berechtigungsprüfung, Anfrageprotokollierung, Ändern von Antworten usw. Fastify bietet verschiedene Arten von Hooks (z. B. onRequest, preHandler, onSend usw.), die es Entwicklern ermöglichen, verschiedene Phasen der Anfrageverarbeitung präzise zu steuern.
Diese Komponenten arbeiten zusammen, um Fastify mit großer Flexibilität und Skalierbarkeit auszustatten und gleichzeitig die hochleistungsfähigen Eigenschaften des Frameworks beizubehalten.
5.5 Lifecycle-Gewichtung
Komponenten in Fastify (Plugins, Dekoratoren, Middleware und Hooks) folgen einer bestimmten Ausführungsreihenfolge und Priorität, die ihren Zeitpunkt des Handelns im Request-Verarbeitungsfluss bestimmt. Das Verständnis dieses Ausführungsflusses ist entscheidend für das Entwerfen effizienter und zuverlässiger Fastify-Anwendungen:
- Plugins: Werden beim Starten der Anwendung geladen und in der Reihenfolge der Registrierung ausgeführt. Nachdem die Anwendung gestartet wurde, werden die Plugin-Einstellungen verfestigt, und die in den Plugins definierten Funktionen (z. B. Routen, Hooks, Dekoratoren) können für jede nachfolgende Anfrage verwendet werden.
- Dekoratoren: Es gibt keine klare Ausführungszeit für sie. Die den dekorierten Objekten (Fastify-Instanz, Request, Reply) hinzugefügten Methoden oder Eigenschaften sind sofort verfügbar und bleiben während des gesamten Lebenszyklus der Objekte gültig.
- Middleware: Wird früh im Verarbeitungsfluss jeder Anfrage ausgeführt, insbesondere vor dem Routenabgleich. Middleware kann die Request- und Reply-Objekte ändern oder entscheiden, ob die Anfrage an den nächsten Prozessor weitergeleitet werden soll.
- Hooks: Folgen einer bestimmten Ausführungsreihenfolge, die sich im Request-Verarbeitungsfluss widerspiegelt:
- onRequest: Wird unmittelbar nach dem Empfang der Anfrage ausgeführt, vor jeder anderen Verarbeitung.
- preParsing: Wird ausgeführt, bevor der Anfrage-Body geparst wird.
- preValidation: Wird vor der Validierung auf Routen-Ebene ausgeführt.
- preHandler: Wird vor der Routen-Verarbeitungsfunktion ausgeführt.
- preSerialization: Wird ausgeführt, bevor die Antwort serialisiert wird, bevor sie an den Client gesendet wird.
- onSend: Wird ausgeführt, bevor die Antwort an den Client gesendet wird, jedoch nach der Serialisierung.
- onResponse: Wird ausgeführt, nachdem die Antwort vollständig an den Client gesendet wurde.
Fähigkeit zur Unterbrechung
- Plugins: Nehmen nicht direkt an der Unterbrechung der Anfrageverarbeitung teil, können aber Hooks oder Middleware registrieren, die den Prozess beeinflussen.
- Dekoratoren: Steuern den Prozess nicht, daher nehmen sie nicht an Unterbrechungen teil.
- Middleware: Kann den Request-Verarbeitungsfluss unterbrechen. Beispielsweise kann das Nichtaufrufen von next() oder das Senden einer Antwort die nachfolgende Verarbeitung stoppen.
- Hooks: Bestimmte Hooks (z. B. preHandler) können entscheiden, ob die Verarbeitung der Anfrage fortgesetzt oder direkt eine Antwort gesendet werden soll, wodurch der nachfolgende Prozess unterbrochen wird.
Das Verständnis der Ausführungsreihenfolge und der Unterbrechungsfähigkeiten dieser Komponenten ist entscheidend für das Erstellen von Fastify-Anwendungen, die sich wie erwartet verhalten.
6. Lebenszyklus
Normaler Prozess
- [Eingehende Anfrage]: Eine neue Anfrage geht im System ein.
- ↓
- [Routing]: Ermitteln Sie die der Anfrage entsprechende Route.
- ↓
- [Instanz-Logger]: Protokollieren Sie die mit der Anfrage verbundenen Instanzprotokolle.
- ↓
- [onRequest-Hook]: Führen Sie die Funktion
onRequest
Hook aus, die für die einheitliche Anfragevorverarbeitung verwendet werden kann. - ↓
- [preParsing-Hook]: Führen Sie die Hook-Funktion aus, bevor der Anfragetext geparst wird.
- ↓
- [Parsing]: Analysieren Sie den Anfragetext.
- ↓
- [preValidation-Hook]: Führen Sie die Hook-Funktion vor der Routenvalidierung aus.
- ↓
- {Validierung}: Führen Sie die Routenvalidierung durch:
- Wenn die Validierung fehlschlägt→[400]: Geben Sie eine 400-Fehlerantwort zurück.
- Wenn die Validierung erfolgreich ist→↓
- [preHandler Hook]: Führen Sie die Hook-Funktion vor der Routenverarbeitungsfunktion aus, und es können Operationen wie die Berechtigungsprüfung durchgeführt werden.
- ↓
- [Benutzer Handler]: Führen Sie die benutzerdefinierte Routenverarbeitungsfunktion aus.
- ↓
- [Antwort]: Bereiten Sie den Antwortinhalt vor.
- ↓
- [preSerialization Hook]: Führen Sie die Hook-Funktion aus, bevor die Antwort serialisiert wird.
- ↓
- [onSend Hook]: Führen Sie die Hook-Funktion aus, bevor die Antwort gesendet wird.
- ↓
- [Ausgehende Antwort]: Senden Sie die Antwort.
- ↓
- [onResponse Hook]: Führen Sie die Hook-Funktion aus, nachdem die Antwort vollständig gesendet wurde.
7. Kapselung
Der Encapsulation Context
von Fastify ist eine seiner Basisfunktionen. Der Encapsulation Context bestimmt, welche Dekoratoren, registrierten Hooks und Plugins für Routen verwendet werden können. Jeder Kontext erbt nur vom übergeordneten Kontext, und der übergeordnete Kontext kann nicht auf Entitäten in seinen Nachfolgekontexten zugreifen. Wenn die Standardsituation die Anforderungen nicht erfüllt, kann fastify-plugin verwendet werden, um den Encapsulation Context aufzubrechen, wodurch der in den Nachfolgekontexten registrierte Inhalt im enthaltenden übergeordneten Kontext verfügbar wird.
8. JSON-Schema-Validierung für Routen
JSON-Schema wird in Fastify mit Routen kombiniert, um Client-Anfragedaten zu validieren und Antwortdaten zu formatieren. Durch das Definieren von JSON-Schemas kann sichergestellt werden, dass die eingehenden Anfragedaten bestimmte Format- und Typanforderungen erfüllen, und gleichzeitig die Struktur der Antwortdaten gesteuert, wodurch die Robustheit und Sicherheit der API verbessert wird.
Beispielcode
const fastify = require("fastify")(); // JSON-Schema definieren const userSchema = { type: "object", required: ["username", "email", "gender"], properties: { username: { type: "string" }, email: { type: "string", format: "email" }, gender: { type: "string", minimum: "male" }, }, }; fastify.route({ method: "POST", url: "/create-user", schema: { body: userSchema, // Verwenden Sie JSON-Schema, um den Anfragetext zu validieren response: { 200: { type: "object", properties: { success: { type: "boolean" }, id: { type: "string" }, }, }, }, }, handler: (request, reply) => { // Anfrage-Logik behandeln // Nehmen wir an, dass das Erstellen eines Benutzers erfolgreich ist und die Benutzer-ID zurückgegeben wird reply.send({ success: true, id: "leapcell" }); }, }); fastify.listen(3000, (err) => { if (err) throw err; console.log("Server is running on http://localhost:3000"); });
In diesem Beispiel:
userSchema
wird definiert und beschreibt das erwartete Format des Anfragetexts, einschließlich erforderlicher Felder und der Typen jedes Felds.- In der Routenkonfiguration wird
userSchema
über die Eigenschaftschema
auf den Anfragetext (body
) angewendet, und Fastify validiert automatisch, ob die eingehenden Anfragedaten dem definierten Schema entsprechen. - Das
schema
der Antwort wird definiert, um sicherzustellen, dass die Antwortdatenstruktur den Erwartungen entspricht.
Auf diese Weise kann sichergestellt werden, dass alle eingehenden Anfragen streng validiert werden und alle Antworten dem 预定格式 entsprechen, wodurch die Robustheit der API und die Vorhersagbarkeit für Benutzer erhöht werden.
9. Beispiele
9.1 Hooks behandeln Probleme mit dem Anmeldestatus
const fastify = require("fastify")({ logger: true }); const secureSession = require("fastify-secure-session"); // Registrieren Sie das Session-Plugin fastify.register(secureSession, { secret: "averylognsecretkey", // Es sollte ein langer und komplexer geheimer Schlüssel verwendet werden cookie: { path: "/", // Konfigurieren Sie bei Bedarf weitere Cookie-Optionen }, }); // Wenden Sie den preHandler-Hook nur auf /api/a und /api/c an fastify.addHook("preHandler", (request, reply, done) => { if ( (request.routerPath === "/api/1" || request.routerPath === "/api/2") && !request.session.user ) { request.session.redirectTo = request.raw.url; reply.redirect(302, "/login"); done(); } else { done(); } }); // Route, die keine Sitzungsüberprüfung erfordert fastify.get("/api/2", (req, reply) => { reply.send({ message: "Zugriff für /api/2 gewährt" }); }); // Route, die eine Sitzungsüberprüfung erfordert fastify.get("/api/1", (req, reply) => { reply.send({ message: "Zugriff für /api/1 gewährt" }); }); fastify.get("/api/3", (req, reply) => { reply.send({ message: "Zugriff für /api/3 gewährt" }); }); // Route für die Anmeldeseite fastify.get("/login", (req, reply) => { reply.send(`Login form goes here. POST to /login to authenticate.`); }); // Anmeldelogik fastify.post("/login", (req, reply) => { const { username, password } = req.body; if (username === "user" && password === "password") { req.session.user = username; const redirectTo = req.session.redirectTo || "/"; delete req.session.redirectTo; reply.redirect(302, redirectTo); } else { reply.code(401).send({ error: "Unauthorized" }); } }); // Starten Sie den Server fastify.listen(3000, (err) => { if (err) { fastify.log.error(err); process.exit(1); console.log(`Server listening on http://localhost:3000`); });
9.2 Parameter begrenzen
Das folgende Beispiel erfordert, dass die Parameter a
und b
in einer POST-Anfrage übergeben werden müssen:
const fastify = require("fastify")(); const postSchema = { schema: { body: { type: "object", required: ["a", "b"], properties: { a: { type: "string" }, b: { type: "string" } } }, response: { // Wenn nicht vorhanden, wird standardmäßig ein 400-Fehler zurückgegeben, und der Rückgabetyp von 400 kann hier geändert werden 400: { type: "object", properties: { statusCode: { type: "number" }, error: { type: "string" }, message: { type: "string" } } } }, // Hier können Sie die obige Standard-Abfangstrategie abfangen preValidation: (request, reply, done) => { if (!request.body ||!request.body.a ||!request.body.b) { reply .code(400) .send({ error: "Bad Request", message: "Missing required parameters" }); return; } done(); } }; fastify.post("/api/data", postSchema, (request, reply) => { // Wenn es bis hierher kommt, bedeutet dies, dass sowohl die Parameter a als auch b die Überprüfung bestanden haben reply.send({ message: "Success" }); }); fastify.listen(3000, (err) => { if (err) { console.error(err); process.exit(1); } console.log("Server listening on port 3000"); });
Wenn Sie den preValidation
-Hook und das benutzerdefinierte Response Schema
in der Route nicht definieren, gibt Fastify standardmäßig einen 400-Fehler (Bad Request) zurück, wenn der body
einer POST-Anfrage nicht dem definierten JSON-Schema entspricht. Der Antworttext dieses Fehlers enthält Informationen darüber, welche Felder die Anforderungen nicht erfüllen. Diese Informationen werden jedoch automatisch von Fastify generiert und sind möglicherweise nicht so spezifisch oder eindeutig wie eine benutzerdefinierte Fehlermeldung. Standardmäßig, wenn nur der Parameter a
übergeben wird und der Parameter b
fehlt, gibt Fastify eine Antwort mit Fehlerdetails zurück, ähnlich wie:
{ "statusCode": 400, "error": "Bad Request", "message": "body should have required property 'b'" }
Leapcell: Das Beste von Serverless Webhosting
Abschließend empfehle ich eine Plattform, die sich am besten für die Bereitstellung von NodeJS-Diensten eignet: Leapcell
🚀 Mit Ihrer Lieblingssprache erstellen
Entwickeln Sie mühelos in JavaScript, Python, Go oder Rust.
🌍 Unbegrenzte Projekte kostenlos bereitstellen
Zahlen Sie nur für das, was Sie verwenden – keine Anfragen, keine Gebühren.
⚡ Pay-as-You-Go, keine versteckten Kosten
Keine Leerlaufgebühren, nur nahtlose Skalierbarkeit.
📖 Entdecken Sie unsere Dokumentation
🔹 Folgen Sie uns auf Twitter: @LeapcellHQ