Express.js十多年来一直主导着Node.js Web开发,但Hono作为专为边缘计算时代设计的现代替代品正在崛起。本全面比较考察性能、开发者体验、生态系统和真实用例,帮助你为下一个项目选择合适的框架。
TL;DR - 快速总结
Hono提供卓越的性能(快5倍以上),可在任何JavaScript运行时(Node.js、Deno、Bun、Cloudflare Workers)上运行,并具有现代的TypeScript优先设计。Express.js对于遗留项目和需要广泛中间件生态系统的团队仍然是安全的选择。对于2025年的新项目,推荐使用Hono。
核心要点
- Hono比Express.js快5-10倍,内存使用量显著更低
- Hono随处运行:Node.js、Deno、Bun、Cloudflare Workers、AWS Lambda
- Express.js拥有最大的中间件生态系统,但许多已过时
- Hono是TypeScript优先,开箱即用提供出色的类型推断
- 两个框架有类似的API,使迁移相对容易
- Hono的内置中间件涵盖大多数常见用例
什么是Hono?
Hono是一个轻量级、快速、可移植的Web框架,专为边缘计算设计。Hono(日语意为"火焰")由Yusuke Wada于2022年创建,优先考虑速度和可移植性。它使用Web标准Request/Response API,允许它在任何JavaScript运行时上无需修改即可运行。
什么是Express.js?
Express.js创建于2009年,是Node.js Web框架的事实标准。其极简、无倾向性的方法使其成为无数Web应用和API的基础。Express在npm上每周有超过3000万次下载,仍然是最广泛使用的Node.js框架。
架构对比
| 特性 | Express.js | Hono |
|---|---|---|
| 首次发布 | 2009 | 2022 |
| 设计目标 | Simplicity | Speed + Portability |
| API标准 | Node.js req/res | Web Standards (Request/Response) |
| TypeScript支持 | 需额外配置 | 原生支持 |
| 运行时支持 | Node.js only | Node.js, Deno, Bun, Workers |
| 包大小 | ~210KB | ~20KB |
| 依赖数量 | 30+ | 0 |
性能对比
在AWS c6i.xlarge实例上使用wrk的性能基准测试:
Hello World 基准测试
使用100个并发连接进行简单JSON响应测试:
// Express Hello World
import express from 'express';
const app = express();
app.get('/', (req, res) => {
res.json({ message: 'Hello World' });
});
app.listen(3000);
// Hono Hello World
import { Hono } from 'hono';
const app = new Hono();
app.get('/', (c) => {
return c.json({ message: 'Hello World' });
});
export default app;| 指标 | Express.js | Hono | 提升 |
|---|---|---|---|
| 请求/秒 | ~12,000 | ~68,000 | 5.7x |
| 延迟 (p99) | 18ms | 3ms | 6x |
| 内存使用 (启动) | ~45MB | ~8MB | 5.6x |
| 内存使用 (负载下) | ~120MB | ~25MB | 4.8x |
中间件性能
测试常用中间件(CORS、请求体解析、日志记录):
// Express with middleware
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import bodyParser from 'body-parser';
const app = express();
app.use(cors());
app.use(helmet());
app.use(morgan('tiny'));
app.use(bodyParser.json());
app.post('/api/users', (req, res) => {
res.json({ created: req.body });
});
// Hono with middleware
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { bodyLimit } from 'hono/body-limit';
const app = new Hono();
app.use('*', cors());
app.use('*', logger());
app.use('*', bodyLimit({ maxSize: 1024 * 1024 })); // 1MB
app.post('/api/users', async (c) => {
const body = await c.req.json();
return c.json({ created: body });
});| 配置 | Express.js | Hono |
|---|---|---|
| CORS + Helmet + Logger + Body Parser | ~8,500 req/s | ~52,000 req/s |
| 仅JSON响应 | ~12,000 req/s | ~68,000 req/s |
功能对比
比较内置功能和生态系统:
| 功能 | Express.js | Hono |
|---|---|---|
| 路由 | 内置 | 内置 (含模式匹配) |
| 中间件 | 需安装 | 丰富的内置中间件 |
| CORS | cors包 | hono/cors (内置) |
| Body解析 | body-parser包 | 内置 |
| JWT认证 | jsonwebtoken包 | hono/jwt (内置) |
| Cookie处理 | cookie-parser包 | hono/cookie (内置) |
| 缓存 | 需外部包 | hono/cache (内置) |
| HTML模板 | 需选择模板引擎 | JSX支持内置 |
| 验证 | joi/yup/zod | @hono/zod-validator |
| OpenAPI/Swagger | 需配置 | @hono/zod-openapi |
代码示例
类似的API使迁移变得简单直接:
Express.js
// Express.js - Complete API example
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import jwt from 'jsonwebtoken';
const app = express();
// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
// Authentication middleware
const authMiddleware = (req, res, next) => {
const token = req.headers.authorization?.split(' ')[1];
if (!token) return res.status(401).json({ error: 'Unauthorized' });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
req.user = decoded;
next();
} catch {
res.status(401).json({ error: 'Invalid token' });
}
};
// Routes
app.get('/api/users', async (req, res) => {
try {
const users = await db.query('SELECT id, email, name FROM users');
res.json({ users });
} catch (error) {
res.status(500).json({ error: 'Database error' });
}
});
app.post('/api/users', async (req, res) => {
const { email, name } = req.body;
try {
const result = await db.query(
'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
[email, name]
);
res.status(201).json({ user: result[0] });
} catch (error) {
res.status(400).json({ error: 'Invalid data' });
}
});
app.get('/api/users/:id', authMiddleware, async (req, res) => {
const { id } = req.params;
try {
const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
if (!user.length) return res.status(404).json({ error: 'Not found' });
res.json({ user: user[0] });
} catch (error) {
res.status(500).json({ error: 'Database error' });
}
});
// Error handling
app.use((err, req, res, next) => {
console.error(err);
res.status(500).json({ error: 'Internal server error' });
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});Hono
// Hono - Complete API example
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
import { jwt } from 'hono/jwt';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const app = new Hono();
// Global middleware
app.use('*', logger());
app.use('*', cors());
// Validation schemas
const userSchema = z.object({
email: z.string().email(),
name: z.string().min(1),
});
// Public routes
app.get('/api/users', async (c) => {
try {
const users = await db.query('SELECT id, email, name FROM users');
return c.json({ users });
} catch {
return c.json({ error: 'Database error' }, 500);
}
});
app.post('/api/users', zValidator('json', userSchema), async (c) => {
const { email, name } = c.req.valid('json');
try {
const result = await db.query(
'INSERT INTO users (email, name) VALUES ($1, $2) RETURNING *',
[email, name]
);
return c.json({ user: result[0] }, 201);
} catch {
return c.json({ error: 'Invalid data' }, 400);
}
});
// Protected routes
app.use('/api/users/*', jwt({ secret: process.env.JWT_SECRET! }));
app.get('/api/users/:id', async (c) => {
const id = c.req.param('id');
const payload = c.get('jwtPayload');
try {
const user = await db.query('SELECT * FROM users WHERE id = $1', [id]);
if (!user.length) return c.json({ error: 'Not found' }, 404);
return c.json({ user: user[0] });
} catch {
return c.json({ error: 'Database error' }, 500);
}
});
// Error handling
app.onError((err, c) => {
console.error(`${err}`);
return c.json({ error: 'Internal server error' }, 500);
});
// Not found
app.notFound((c) => {
return c.json({ error: 'Not found' }, 404);
});
export default app;TypeScript体验
TypeScript支持对比:
需要@types/express,类型定义有时过时。请求/响应对象的类型扩展需要额外配置。社区维护的类型可能滞后于新版本。
原生TypeScript编写,一流的类型支持。自动推断路径参数、查询参数和请求体类型。Context对象完全类型化,中间件可以修改类型上下文。
// Hono TypeScript - Type-safe routes
import { Hono } from 'hono';
import { zValidator } from '@hono/zod-validator';
import { z } from 'zod';
const app = new Hono();
// Types are automatically inferred
app.get('/api/users/:id', async (c) => {
// id is typed as string
const id = c.req.param('id');
// query parameters are typed
const page = c.req.query('page'); // string | undefined
// Response is type-checked
return c.json({
id,
name: 'John',
// TypeScript will error if you return wrong type
});
});
// With Zod validation - types flow through
const schema = z.object({
email: z.string().email(),
age: z.number().min(0),
});
app.post('/api/users', zValidator('json', schema), async (c) => {
// validated is typed as { email: string, age: number }
const validated = c.req.valid('json');
// TypeScript knows the exact shape
console.log(validated.email); // ✓
console.log(validated.name); // ✗ TypeScript error!
return c.json({ success: true });
});部署选项
你可以在哪里部署每个框架?
| 平台 | Express.js | Hono |
|---|---|---|
| Node.js | ✓ Native | ✓ Native |
| Deno | 需适配 | ✓ Native |
| Bun | ✓ Compatible | ✓ Native |
| Cloudflare Workers | 需适配器 | ✓ Native |
| Deno Deploy | 需适配器 | ✓ Native |
| Vercel Edge | 需适配器 | ✓ Native |
| AWS Lambda | ✓ serverless-http | ✓ @hono/aws-lambda |
| Fly.io | ✓ Docker | ✓ Docker / Native |
| Railway | ✓ Native | ✓ Native |
从Express迁移到Hono
分步迁移指南:
// Migration: Express to Hono
// 1. Install dependencies
// npm uninstall express cors helmet morgan body-parser
// npm install hono @hono/node-server
// 2. Update imports
// Before:
import express from 'express';
import cors from 'cors';
// After:
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { serve } from '@hono/node-server';
// 3. Update app initialization
// Before:
const app = express();
// After:
const app = new Hono();
// 4. Update middleware
// Before:
app.use(cors());
app.use(express.json());
// After:
app.use('*', cors());
// JSON parsing is built-in, no middleware needed!
// 5. Update route handlers
// Before:
app.get('/users', (req, res) => {
res.json({ users: [] });
});
// After:
app.get('/users', (c) => {
return c.json({ users: [] });
});
// 6. Update error handling
// Before:
app.use((err, req, res, next) => {
res.status(500).json({ error: err.message });
});
// After:
app.onError((err, c) => {
return c.json({ error: err.message }, 500);
});
// 7. Start server (Node.js only)
// Before:
app.listen(3000);
// After:
serve({ fetch: app.fetch, port: 3000 });何时使用每个框架
使用Hono的场景:
- 新项目开发
- 边缘计算/无服务器
- 高性能API
- Cloudflare Workers
- TypeScript优先项目
- 多运行时部署
- 快速原型开发
使用Express的场景:
- 遗留代码维护
- 团队熟悉Express生态
- 依赖特定中间件
- Node.js专用部署
- 企业级应用(已验证)
- 需要丰富文档和教程
结论
在2025年,Hono代表着JavaScript Web框架的未来。其性能优势、运行时可移植性和现代设计使其成为新项目的理想选择。Express.js对于维护现有应用仍然是可靠的选择,但新开发应该认真考虑Hono。Web开发的未来是边缘优先、多运行时和TypeScript原生——这些都是Hono的优势。
FAQ
Hono已经可以用于生产了吗?
是的,Hono已经可以用于生产,被Cloudflare、Deno等公司在生产环境中使用。它已达到4.x版本,API稳定,并积极维护,定期更新。
我可以在Hono中使用Express中间件吗?
不能直接,因为它们有不同的API。然而,Hono有大多数流行Express中间件的等效中间件,许多包可以两者通用。Hono生态系统包括CORS、请求体解析、认证和其他常见中间件。
Hono比Fastify快吗?
在大多数基准测试中,Hono和Fastify具有可比的性能,都比Express快得多。Hono的优势在于其跨运行时的可移植性,而Fastify专门为Node.js优化。
如何将Hono部署到Cloudflare Workers?
Hono无需任何适配器即可在Cloudflare Workers上原生工作。只需使用Web标准API并用wrangler部署。Hono使用Request/Response API使其成为边缘平台的理想选择。
Hono可以在现有项目中替代Express吗?
可以,但需要迁移你的中间件和路由处理器。API足够相似,路由逻辑容易转移。开始时可以一次迁移一个路由,或将Hono用于新的微服务。
Hono支持WebSocket吗?
Hono为Node.js和Deno提供内置WebSocket支持。对于Cloudflare Workers,你可以将Durable Objects与WebSockets一起使用。API简单且文档完善。
Hono适合构建REST API吗?
当然。Hono的内置验证、TypeScript支持和中间件使其非常适合REST API开发。它包括OpenAPI/Swagger集成等常见模式的辅助工具。
Hono中的文件上传呢?
Hono通过hono/multipart中间件内置支持multipart/form-data文件上传。它在所有支持的运行时上一致工作。