express, fastify, hapi, 和 koa 都是 Node.js 生态中成熟的后端 Web 框架,用于构建 API 服务器和 Web 应用。express 是最经典的选择,生态最丰富,适合快速原型和传统项目;fastify 主打高性能和内置 JSON Schema 验证,适合高并发 API;koa 由 Express 原班人马打造,核心更现代且轻量,完全基于 async/await;hapi(现主要为 @hapi/hapi)则侧重配置化和企业级插件系统,适合大型复杂架构。
在 Node.js 后端开发中,选择 Web 框架是架构决策的第一步。express, fastify, hapi, 和 koa 代表了四种不同的设计哲学。作为架构师,我们需要从核心机制、开发体验、性能和维护成本四个维度进行拆解。
框架的核心决定了代码的组织方式。
express 采用传统的中间件栈模式。
req, res 和 next。next() 传递控制权,否则请求会挂起。// express: 中间件链
app.use((req, res, next) => {
console.log('Time:', Date.now());
next(); // 必须调用
});
koa 采用洋葱模型上下文模式。
ctx 上,没有 req 和 res 分离。await next() 控制流程,更直观。// koa: 上下文组合
app.use(async (ctx, next) => {
console.log('Time:', Date.now());
await next(); // 等待下游完成
});
fastify 采用封装钩子模式。
// fastify: 钩子与封装
fastify.addHook('onRequest', async (request, reply) => {
console.log('Time:', Date.now());
// 无需手动调用 next,钩子自动执行
});
hapi 采用配置驱动模式。
// hapi: 扩展点配置
server.ext('onRequest', (request, h) => {
console.log('Time:', Date.now());
return h.continue; // 显式返回继续
});
路由管理方式直接影响项目结构。
express 内置路由实例。
// express: 内置路由
app.get('/users/:id', (req, res) => {
res.send({ id: req.params.id });
});
koa 核心不包含路由。
@koa/router 使用。// koa: 外挂路由
const router = require('@koa/router')();
router.get('/users/:id', ctx => {
ctx.body = { id: ctx.params.id };
});
fastify 内置高性能路由。
// fastify: 内置路由
fastify.get('/users/:id', (req, reply) => {
reply.send({ id: req.params.id });
});
hapi 配置式路由。
// hapi: 配置路由
server.route({
method: 'GET',
path: '/users/{id}',
handler: (request, h) => ({ id: request.params.id })
});
API 的安全性和数据规范性至关重要。
express 完全手动或依赖中间件。
joi, zod 或 express-validator。// express: 手动验证
app.post('/user', (req, res, next) => {
if (!req.body.name) return res.status(400).send('Name required');
next();
});
koa 完全手动或依赖中间件。
koa-joi 等库。ctx 上处理验证逻辑。// koa: 手动验证
router.post('/user', async ctx => {
if (!ctx.request.body.name) {
ctx.status = 400;
ctx.body = 'Name required';
return;
}
});
fastify 内置 JSON Schema 验证。
// fastify: 内置 Schema
fastify.post('/user', {
schema: {
body: { type: 'object', required: ['name'], properties: { name: { type: 'string' } } }
}
}, (req, reply) => {
reply.send(req.body); // 自动序列化
});
hapi 内置验证(基于 Joi)。
validate 选项。// hapi: 内置验证
server.route({
method: 'POST',
path: '/user',
options: {
validate: {
payload: { name: Joi.string().required() }
}
},
handler: (request, h) => request.payload
});
错误处理机制决定了系统的稳定性。
express 依赖错误处理中间件。
(err, req, res, next)。// express: 错误中间件
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
koa 原生 try/catch 支持。
app.on('error') 处理未捕获异常。// koa: 异步捕获
app.use(async (ctx, next) => {
try {
await next();
} catch (err) {
ctx.status = err.status || 500;
ctx.body = err.message;
}
});
fastify 统一错误处理器。
setErrorHandler 集中处理。// fastify: 统一处理
fastify.setErrorHandler((error, request, reply) => {
reply.status(500).send({ error: error.message });
});
hapi 扩展点处理。
onPreResponse 扩展点拦截响应。// hapi: 响应扩展
server.ext('onPreResponse', (request, h) => {
const response = request.response;
if (response.isBoom) {
return h.response({ message: response.message }).code(response.output.statusCode);
}
return h.continue;
});
| 特性 | express | fastify | hapi | koa |
|---|---|---|---|---|
| 核心风格 | 中间件栈 | 钩子与封装 | 配置驱动 | 上下文洋葱模型 |
| 异步模型 | 回调/Async | Async | Async | Async/Await 原生 |
| 路由 | 内置 | 内置 (高性能) | 内置 (配置式) | 需外挂 (@koa/router) |
| 验证 | 手动/中间件 | 内置 JSON Schema | 内置 (Joi) | 手动/中间件 |
| 性能 | 中等 | 极高 | 中等偏低 | 中等 |
| 生态规模 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 学习曲线 | 低 | 中 | 高 | 中 |
express 是稳妥的默认选择 🛡️。如果团队没有特殊性能需求,或者需要快速利用海量现有中间件(如 Passport, Multer),Express 能最大程度降低开发阻力。但在新项目中,需注意异步错误捕获的规范。
fastify 是高性能 API 的首选 🚀。如果构建微服务、高并发网关,或对请求/响应格式有严格 Schema 要求,Fastify 的内置验证和序列化能节省大量代码并提升吞吐量。其插件封装机制也更适合大型团队协作。
hapi 适合企业级规范项目 🏢。如果项目规模巨大,需要严格的配置管理和插件隔离,且团队能接受较陡的学习曲线,Hapi 的架构约束能减少人为错误。注意需迁移至 @hapi 命名空间。
koa 适合现代极简主义 🍃。如果团队偏好函数式编程风格,希望核心轻量且完全掌控中间件组合,Koa 是最佳选择。它没有历史包袱,代码最干净,但需要自己维护路由和验证生态。
最终结论:对于大多数新启动的 Node.js API 项目,fastify 在性能与现代开发体验之间取得了最佳平衡。若追求极致生态兼容性,express 依然可靠。
选择 express 如果你需要最丰富的中间件生态,或者团队熟悉传统的回调风格。它适合快速构建原型、中小型项目,以及需要大量现成社区支持的场景。由于其历史悠久,遇到问题时最容易找到解决方案。
选择 koa 如果你喜欢 async/await 原生支持,想要一个极简的核心,自己组装路由和验证库。它适合希望摆脱回调地狱,追求代码简洁和现代 JavaScript 特性的团队。由于核心小,你需要自己挑选中间件。
选择 fastify 如果你关注极致的性能,或者希望框架内置请求验证和序列化功能。它适合高并发 API 服务,以及对类型安全和 Schema 驱动开发有要求的团队。其插件封装机制也适合大型模块化项目。
选择 hapi 如果你的项目是企业级大型应用,偏好配置优于代码的风格,且需要强大的插件隔离能力。注意需使用 @hapi/hapi 包。它适合对安全性和架构规范性有严格要求的场景,但学习曲线较陡。
Fast, unopinionated, minimalist web framework for Node.js.
This project has a Code of Conduct.
import express from 'express'
const app = express()
app.get('/', (req, res) => {
res.send('Hello World')
})
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000')
})
This is a Node.js module available through the npm registry.
Before installing, download and install Node.js. Node.js 18 or higher is required.
If this is a brand new project, make sure to create a package.json first with
the npm init command.
Installation is done using the
npm install command:
npm install express
Follow our installing guide for more information.
PROTIP Be sure to read the migration guide to v5
The quickest way to get started with express is to utilize the executable express(1) to generate an application as shown below:
Install the executable. The executable's major version will match Express's:
npm install -g express-generator@4
Create the app:
express /tmp/foo && cd /tmp/foo
Install dependencies:
npm install
Start the server:
npm start
View the website at: http://localhost:3000
The Express philosophy is to provide small, robust tooling for HTTP servers, making it a great solution for single page applications, websites, hybrids, or public HTTP APIs.
Express does not force you to use any specific ORM or template engine. With support for over 14 template engines via @ladjs/consolidate, you can quickly craft your perfect framework.
To view the examples, clone the Express repository:
git clone https://github.com/expressjs/express.git --depth 1 && cd express
Then install the dependencies:
npm install
Then run whichever example you want:
node examples/content-negotiation
The Express.js project welcomes all constructive contributions. Contributions take many forms, from code for bug fixes and enhancements, to additions and fixes to documentation, additional tests, triaging incoming pull requests and issues, and more!
See the Contributing Guide for more technical details on contributing.
If you discover a security vulnerability in Express, please see Security Policies and Procedures.
To run the test suite, first install the dependencies:
npm install
Then run npm test:
npm test
For information about the governance of the express.js project, see GOVERNANCE.md.
The original author of Express is TJ Holowaychuk