用Bun.serve构建高性能API服务器:替代Express/NestJS的完整迁移指南

发布时间:2026/7/24 14:52:26

用Bun.serve构建高性能API服务器:替代Express/NestJS的完整迁移指南 用Bun.serve构建高性能API服务器替代Express/NestJS的完整迁移指南Bun到底快在哪里Bun是All-in-one JavaScript运行时内置了运行时替代Node.js包管理器替代npm/yarn测试框架替代Jest/VitestAPI服务器替代Express/Fastify但最让人兴奋的是性能。Bun的Bun.serveAPI用于构建HTTP服务器比Express快4-10倍。性能对比 benchmarkHello World API框架请求/秒单线程延迟P99内存占用Express (Node.js 20)15,00012ms85MBFastify (Node.js 20)38,0006ms65MBBun.serve (Bun 1.0)162,0002ms32MBHono (Bun模式)158,0002ms30MB为什么Bun这么快Zig编写 高度优化的JS引擎JavaScriptCore比V8Node.js用的在启动速度和某些工作负载上更快内置HTTP服务器基于uWebSockets.js这是C编写的高性能HTTP库比Node.js的http.createServer快得多零拷贝和反序列化优化Bun在处理请求体时直接用类型化数组TypedArray避免不必要的内存拷贝Bun.serve快速上手15分钟构建REST API第一步安装Bun# macOS/Linux curl -fsSL https://bun.sh/install | bash # 验证安装 bun --version第二步创建项目mkdir my-bun-api cd my-bun-api bun init # 会问你几个问题选择TypeScript和Server第三步编写API服务器// src/index.ts import { serve } from bun; const apiKeys new Mapstring, { userId: string; rateLimit: number }(); const server serve({ port: 3000, async fetch(req) { const url new URL(req.url); const path url.pathname; const method req.method; // CORS Headers if (method OPTIONS) { return new Response(null, { headers: { Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS, Access-Control-Allow-Headers: Content-Type, X-API-Key, }, }); } // 路由GET /api/health if (path /api/health method GET) { return Response.json({ status: ok, timestamp: Date.now() }); } // 路由POST /api/keys (创建API Key) if (path /api/keys method POST) { const body await req.json(); const apiKey crypto.randomUUID(); // 简化版实际应该用更安全的生成方式 apiKeys.set(apiKey, { userId: body.userId, rateLimit: body.rateLimit || 100 }); return Response.json({ apiKey }); } // 路由GET /api/data (需要API Key) if (path /api/data method GET) { const apiKey req.headers.get(X-API-Key); if (!apiKey || !apiKeys.has(apiKey)) { return Response.json({ error: Unauthorized }, { status: 401 }); } return Response.json({ data: 机密数据, userId: apiKeys.get(apiKey)!.userId }); } // 404 return new Response(Not Found, { status: 404 }); }, // 错误处理 error(error) { console.error(Server error:, error); return new Response(Internal Server Error, { status: 500 }); }, }); console.log( Server running at http://localhost:${server.port});运行bun run src/index.ts路由组织从if-else到结构化路由上面的例子用if-else做路由匹配适合简单API。复杂API需要用路由库。推荐方案Hono为Bun优化的轻量级Web框架Hono是超快的Web框架支持Bun、Cloudflare Workers、Deno等多种运行时。它的API设计类似Express但性能高得多。安装bun add hono用Hono重写上面的API// src/app.ts import { Hono } from hono; import { serve } from hono/node-server; // Hono的Bun适配器 const app new Hono(); // 中间件CORS app.use(*, async (c, next) { c.header(Access-Control-Allow-Origin, *); c.header(Access-Control-Allow-Methods, GET, POST, PUT, DELETE, OPTIONS); if (c.req.method OPTIONS) return c.text(, 204); await next(); }); // 路由 app.get(/api/health, (c) { return c.json({ status: ok, timestamp: Date.now() }); }); app.post(/api/keys, async (c) { const body await c.req.json(); const apiKey crypto.randomUUID(); // 存储到数据库这里简化为内存 return c.json({ apiKey }); }); app.get(/api/data, async (c) { const apiKey c.req.header(X-API-Key); if (!apiKey) return c.json({ error: Unauthorized }, 401); return c.json({ data: 机密数据 }); }); // 404 app.notFound((c) { return c.json({ error: Not Found }, 404); }); // 错误处理 app.onError((err, c) { console.error(Error:, err); return c.json({ error: Internal Server Error }, 500); }); // 启动服务器 serve({ fetch: app.fetch, port: 3000 }, (info) { console.log( Server running at http://localhost:${info.port}); });Hono的优势类型安全如果用TypeScriptHono能提供完整的类型推断中间件生态有官方中间件库hono/node-serverhono/loggerhono/body-parser等多运行时支持同一份代码可以跑在Bun、Cloudflare Workers、Deno上数据库集成Bun Prisma/Bun SQLiteBun内置了Bun.sqlSQLite客户端和Bun.sqliteSQLite数据库也支持Prisma。方案一用Bun.sqlite轻量级适合小项目// src/db.ts import { Database } from bun:sqlite; const db new Database(app.db, { create: true }); // 初始化表 db.run( CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, email TEXT UNIQUE NOT NULL, created_at INTEGER DEFAULT (unixepoch()) ) ); export default db;在API里使用import db from ./db; app.post(/api/users, async (c) { const body await c.req.json(); try { const result db.prepare(INSERT INTO users (id, email) VALUES (?, ?)).run(crypto.randomUUID(), body.email); return c.json({ userId: result.lastInsertRowid }); } catch (error: any) { if (error.message.includes(UNIQUE)) { return c.json({ error: Email already exists }, 400); } throw error; } }); app.get(/api/users/:id, (c) { const user db.prepare(SELECT * FROM users WHERE id ?).get(c.req.param(id)); if (!user) return c.json({ error: User not found }, 404); return c.json(user); });方案二用Prisma适合复杂项目Bun兼容Prisma需要Prisma 5.0。bun add prisma prisma/client bunx prisma init bunx prisma generate bunx prisma db push然后用prisma/client正常查询——Bun的运行时会自动处理。部署从本地开发到生产环境本地开发用--hot自动重启bun run --hot src/index.ts--hot会在文件变化时自动重启服务器类似Node.js的nodemon。生产环境部署用bun build打包Bun可以把你的项目打包成单个可执行文件或优化的JS Bundle。# 打包成优化的JS Bundle bun build src/index.ts --outdir ./dist --target bun # 运行打包后的文件启动速度更快 bun run dist/index.js用Docker部署# Dockerfile FROM oven/bun:1 as builder WORKDIR /app COPY package.json bun.lockb ./ RUN bun install COPY . . RUN bun build src/index.ts --outdir /dist --target bun FROM oven/bun:1 WORKDIR /app COPY --frombuilder /dist ./dist COPY --frombuilder /app/package.json ./ EXPOSE 3000 CMD [bun, run, /dist/index.js]部署到云平台Fly.io原生支持Bunfly.toml里设置[build.args] BUILD_COMMANDbun install bun build src/index.ts --outdir /distRailway在railway.toml里设置buildCommand bun install和startCommand bun run dist/index.jsVercel目前对Bun的支持有限建议用Bun.serve的API部署到Fly.io或Railway迁移策略从Node.js/Express到Bun场景一新项目直接用Bun Hono。这是最快获得高性能API的路径。场景二现有Express项目不需要全部重写。可以用Bun的bun upgrade命令把Node.js替换成Bun运行时大部分Express代码可以直接跑在Bun上逐步把性能瓶颈API迁移到Bun.serve或Hono兼容性检查Bun兼容大部分Node.js API如fs、path、crypto但有一些差异。用bun test运行你的现有测试看是否有失败。# 运行现有测试如果之前用Jest bun test结论Bun.serve Hono的组合让独立开发者能以极简代码获得极致性能。对于API服务器、微服务、实时应用这是目前技术栈里性能/复杂度比最高的选择。关键是理解Bun的性能优势来自哪里——不是魔法而是更底层的优化和零拷贝设计。掌握这些你就能构建出成本更低、性能更好的后端服务。

相关新闻