elysia、express、hapi 和 koa 都是用于构建 Web 服务器和 API 的 JavaScript 框架,但它们的设计理念和运行环境有所不同。express 是最经典的选择,拥有庞大的生态系统,适合大多数 Node.js 项目。koa 由 Express 原班人马打造,更现代,基于 async/await,适合喜欢轻量级控制的开发者。hapi 强调配置化和安全性,常用于企业级应用。elysia 是新兴框架,专为 Bun 运行时设计,追求极致的性能和 TypeScript 体验。
这四个框架都是 JavaScript 生态中构建 Web 服务的重要工具,但它们的底层逻辑和适用场景差异很大。express 是老牌标准,koa 是它的现代继承者,hapi 侧重企业配置,而 elysia 则是针对 Bun 运行时的高性能新秀。让我们从实际工程角度对比它们如何处理常见问题。
elysia 专为 Bun 运行时设计,利用 Bun 的原生 API 实现极速启动和低内存占用。
// elysia: 专为 Bun 优化
import { Elysia } from 'elysia';
new Elysia()
.get('/', () => 'Hello Bun')
.listen(3000);
express 运行在 Node.js 上,启动速度快,生态最成熟,兼容所有 Node 版本。
// express: 标准 Node.js 环境
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('Hello Node'));
app.listen(3000);
hapi 同样基于 Node.js,启动时需要进行较多的配置初始化,适合大型服务。
// hapi: 配置驱动的 Node 服务
import Hapi from '@hapi/hapi';
const init = async () => {
const server = Hapi.server({ port: 3000 });
await server.start();
};
init();
koa 基于 Node.js,轻量级,启动开销小,但需要手动组合中间件。
// koa: 轻量 Node 环境
import Koa from 'koa';
const app = new Koa();
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
elysia 内置路由和基于 TypeBox 的验证,TypeScript 类型自动推断,无需额外库。
// elysia: 内置验证与类型推断
import { Elysia, t } from 'elysia';
new Elysia()
.post('/user', ({ body }) => body, {
body: t.Object({
name: t.String(),
age: t.Number()
})
})
.listen(3000);
express 路由简单,但验证需要第三方中间件(如 Joi 或 express-validator)。
// express: 手动添加验证中间件
import express from 'express';
import { check } from 'express-validator';
const app = express();
app.post('/user',
check('name').isString(),
(req, res) => res.send(req.body)
);
app.listen(3000);
hapi 路由配置详细,内置强大的 Joi 验证,适合复杂规则。
// hapi: 配置化路由与验证
import Hapi from '@hapi/hapi';
import Joi from 'joi';
const server = Hapi.server({ port: 3000 });
server.route({
method: 'POST',
path: '/user',
options: {
validate: {
payload: Joi.object({ name: Joi.string() })
}
},
handler: (request, h) => request.payload
});
koa 本身无路由,需配合 koa-router,验证也需额外中间件。
// koa: 组合式路由与验证
import Koa from 'koa';
import Router from '@koa/router';
const app = new Koa();
const router = new Router();
router.post('/user', ctx => {
ctx.body = ctx.request.body;
});
app.use(router.routes());
app.listen(3000);
elysia 使用统一的上下文对象,插件系统简单,类型安全。
// elysia: 插件与上下文
import { Elysia } from 'elysia';
const logger = new Elysia()
.onRequest(({ set, request }) => {
console.log(request.url);
});
new Elysia()
.use(logger)
.get('/', () => 'Logged')
.listen(3000);
express 使用 req 和 res 两个对象,中间件通过 next() 传递控制流。
// express: 经典 req/res 模式
import express from 'express';
const app = express();
app.use((req, res, next) => {
console.log(req.url);
next();
});
app.listen(3000);
hapi 使用 request 和 h (response toolkit) 对象,生命周期扩展点丰富。
// hapi: 生命周期扩展
import Hapi from '@hapi/hapi';
const server = Hapi.server({ port: 3000 });
server.ext('onRequest', (request, h) => {
console.log(request.path);
return h.continue;
});
koa 使用单一 ctx 对象,封装了 req 和 res,异步流程更清晰。
// koa: 统一 ctx 对象
import Koa from 'koa';
const app = new Koa();
app.use(async (ctx, next) => {
console.log(ctx.url);
await next();
});
app.listen(3000);
elysia 提供全局错误处理钩子,类型安全,易于统一响应格式。
// elysia: 全局错误钩子
import { Elysia, ValidationError } from 'elysia';
new Elysia()
.onError(({ code, error }) => {
if (code === 'VALIDATION') return error.all;
})
.listen(3000);
express 依赖专门的错误处理中间件(四个参数的函数)。
// express: 错误处理中间件
import express from 'express';
const app = express();
app.use((err, req, res, next) => {
res.status(500).send(err.message);
});
app.listen(3000);
hapi 内置强大的错误策略配置,可全局捕获并格式化。
// hapi: 配置化错误策略
import Hapi from '@hapi/hapi';
const server = Hapi.server({ port: 3000 });
server.events.on('request', (request, event) => {
if (event.error) console.error(event.error);
});
koa 使用 app.on('error') 监听,或在中间件 try/catch 处理。
// koa: 事件监听与 try/catch
import Koa from 'koa';
const app = new Koa();
app.use(async ctx => {
try {
throw new Error('Oops');
} catch (err) {
ctx.status = 500;
ctx.body = err.message;
}
});
app.listen(3000);
尽管实现方式不同,这四个框架都解决了 Web 服务的基本需求。
// 所有框架都支持设置状态码
// elysia: ({ set }) => { set.status = 201; }
// express: res.status(201)
// hapi: h.response().code(201)
// koa: ctx.status = 201
// 所有框架都支持日志中间件
// 逻辑类似:记录 URL -> 调用下一步 -> 记录时间
// 所有框架都可连接 Redis
// 使用各自的 HTTP 客户端或专用库
| 特性 | elysia | express | hapi | koa |
|---|---|---|---|---|
| 运行时 | 🚀 Bun (主要) | 🟢 Node.js | 🟢 Node.js | 🟢 Node.js |
| 路由 | 🧩 内置,类型安全 | 🧩 内置,简单 | 🛠️ 配置驱动 | 🔌 需第三方 |
| 验证 | ✅ 内置 (TypeBox) | 🔌 需第三方 | ✅ 内置 (Joi) | 🔌 需第三方 |
| 上下文 | 📦 统一对象 | 📄 req/res 分离 | 📄 request/h | 📦 ctx 统一 |
| 错误处理 | 🎯 全局钩子 | 🎯 中间件 | 🎯 策略配置 | 🎯 事件/try |
| 学习曲线 | 📈 中等 (需懂 Bun) | 📉 低 | 📈 高 | 📉 低 |
express 是稳妥的选择 🛡️。如果你需要快速上手、寻找现成解决方案或维护旧项目,它的社区资源无人能及。
elysia 是未来的方向 🚀。如果你能接受 Bun 运行时,想要最快的速度和最好的 TypeScript 体验,它是新项目的最佳候选。
hapi 是企业的堡垒 🏢。适合需要严格规范、复杂配置和内置安全策略的大型团队。
koa 是极简主义者的工具 🎨。如果你想要 Express 的灵活但讨厌回调地狱,且愿意自己组装路由和验证,它很合适。
核心思考:不要只看流行度。如果你的团队熟悉 Node.js 且需要稳定,选 express 或 koa。如果你追求性能极限且愿意尝试新技术,选 elysia。如果项目受严格合规要求约束,选 hapi。
如果你需要最稳定的生态系统、大量的中间件支持以及广泛的社区资源,选择 express。它适合传统 Node.js 项目、快速原型开发以及需要大量现成插件的场景。
如果你喜欢 Express 的简洁但想要更现代的 async/await 语法,且希望框架更轻量,选择 koa。它适合希望完全控制中间件流程且不需要 Express 历史包袱的开发者。
如果你追求极致性能且愿意使用 Bun 运行时,选择 elysia。它内置 TypeScript 支持和验证,开发体验现代,适合新项目尤其是高性能 API 服务。
如果你在企业环境中工作,需要严格的配置管理、内置验证和强大的安全性策略,选择 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