express vs koa vs elysia vs hapi
Node.js 与 Bun 后端框架选型指南
expresskoaelysiahapi类似的npm包:

Node.js 与 Bun 后端框架选型指南

elysiaexpresshapikoa 都是用于构建 Web 服务器和 API 的 JavaScript 框架,但它们的设计理念和运行环境有所不同。express 是最经典的选择,拥有庞大的生态系统,适合大多数 Node.js 项目。koa 由 Express 原班人马打造,更现代,基于 async/await,适合喜欢轻量级控制的开发者。hapi 强调配置化和安全性,常用于企业级应用。elysia 是新兴框架,专为 Bun 运行时设计,追求极致的性能和 TypeScript 体验。

npm下载趋势

3 年

GitHub Stars 排名

统计详情

npm包名称
下载量
Stars
大小
Issues
发布时间
License
express102,848,05269,06075.4 kB2146 个月前MIT
koa7,375,30635,71165 kB3210 天前MIT
elysia476,51918,4271.1 MB3162 个月前MIT
hapi104,89214,787-617 年前BSD-3-Clause

Elysia vs Express vs Hapi vs Koa:性能、架构与开发体验深度对比

这四个框架都是 JavaScript 生态中构建 Web 服务的重要工具,但它们的底层逻辑和适用场景差异很大。express 是老牌标准,koa 是它的现代继承者,hapi 侧重企业配置,而 elysia 则是针对 Bun 运行时的高性能新秀。让我们从实际工程角度对比它们如何处理常见问题。

🚀 运行环境与启动:Bun 极速 vs Node 稳定

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);

🗺️ 路由与验证:内置智能 vs 手动组合

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);

🧩 中间件与上下文:请求响应对象 vs 统一上下文

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 使用 reqres 两个对象,中间件通过 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 使用 requesth (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 对象,封装了 reqres,异步流程更清晰。

// koa: 统一 ctx 对象
import Koa from 'koa';

const app = new Koa();
app.use(async (ctx, next) => {
  console.log(ctx.url);
  await next();
});
app.listen(3000);

⚠️ 错误处理:集中式 vs 分散式

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 服务的基本需求。

1. 🌐 基于 HTTP 协议

  • 都处理请求、响应、头部和状态码。
  • 支持 RESTful API 设计。
// 所有框架都支持设置状态码
// elysia: ({ set }) => { set.status = 201; }
// express: res.status(201)
// hapi: h.response().code(201)
// koa: ctx.status = 201

2. 🔌 中间件机制

  • 都允许通过中间件扩展功能(日志、认证、解析)。
  • 支持顺序执行请求处理逻辑。
// 所有框架都支持日志中间件
// 逻辑类似:记录 URL -> 调用下一步 -> 记录时间

3. 🛡️ 生态系统支持

  • 都有社区贡献的插件库。
  • 支持连接数据库、缓存等常见服务。
// 所有框架都可连接 Redis
// 使用各自的 HTTP 客户端或专用库

📊 总结:关键差异对比

特性elysiaexpresshapikoa
运行时🚀 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 且需要稳定,选 expresskoa。如果你追求性能极限且愿意尝试新技术,选 elysia。如果项目受严格合规要求约束,选 hapi

如何选择: express vs koa vs elysia vs hapi

  • express:

    如果你需要最稳定的生态系统、大量的中间件支持以及广泛的社区资源,选择 express。它适合传统 Node.js 项目、快速原型开发以及需要大量现成插件的场景。

  • koa:

    如果你喜欢 Express 的简洁但想要更现代的 async/await 语法,且希望框架更轻量,选择 koa。它适合希望完全控制中间件流程且不需要 Express 历史包袱的开发者。

  • elysia:

    如果你追求极致性能且愿意使用 Bun 运行时,选择 elysia。它内置 TypeScript 支持和验证,开发体验现代,适合新项目尤其是高性能 API 服务。

  • hapi:

    如果你在企业环境中工作,需要严格的配置管理、内置验证和强大的安全性策略,选择 hapi。它适合对稳定性和规范性要求极高的大型系统。

express的README

Express Logo

Fast, unopinionated, minimalist web framework for Node.js.

This project has a Code of Conduct.

Table of contents

NPM Version NPM Downloads Linux Build Test Coverage OpenSSF Scorecard Badge

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')
})

Installation

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.

Features

  • Robust routing
  • Focus on high performance
  • Super-high test coverage
  • HTTP helpers (redirection, caching, etc)
  • View system supporting 14+ template engines
  • Content negotiation
  • Executable for generating applications quickly

Docs & Community

PROTIP Be sure to read the migration guide to v5

Quick Start

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

Philosophy

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.

Examples

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

Contributing

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.

Security Issues

If you discover a security vulnerability in Express, please see Security Policies and Procedures.

Running Tests

To run the test suite, first install the dependencies:

npm install

Then run npm test:

npm test

Current project team members

For information about the governance of the express.js project, see GOVERNANCE.md.

The original author of Express is TJ Holowaychuk

List of all contributors

TC (Technical Committee)

TC emeriti members

TC emeriti members

Triagers

Triagers emeriti members

Emeritus Triagers

License

MIT