Documentation Index
Fetch the complete documentation index at: https://bun.zhcndoc.com/llms.txt
Use this file to discover all available pages before exploring further.
你可以通过使用 routes 属性(用于静态路径、参数和通配符)或通过 fetch 方法处理未匹配请求,向 Bun.serve() 添加路由。
Bun.serve() 的路由器建立在 uWebSocket 的 基于树的方式 之上,加入了 SIMD 加速的路由参数解码 和 JavaScriptCore 结构缓存,以推动现代硬件所能达到的性能极限。
基本设置
server.tsBun.serve({
routes: {
"/": () => new Response("首页"),
"/api": () => Response.json({ success: true }),
"/users": async () => Response.json({ users: [] }),
},
fetch() {
return new Response("未匹配路由");
},
});
Bun.serve() 中的路由接收一个 BunRequest(继承自 Request)并返回一个 Response 或 Promise<Response>。这让发送和接收 HTTP 请求时可复用相同代码。
// 简化示例
interface BunRequest<T extends string> extends Request {
params: Record<T, string>;
readonly cookies: CookieMap;
}
异步路由
Async/await
你可以在路由处理函数中使用 async/await 返回 Promise<Response>。
import { sql, serve } from "bun";
serve({
port: 3001,
routes: {
"/api/version": async () => {
const [version] = await sql`SELECT version()`;
return Response.json(version);
},
},
});
Promise
你也可以直接从路由处理函数返回一个 Promise<Response>。
import { sql, serve } from "bun";
serve({
routes: {
"/api/version": () => {
return new Promise(resolve => {
setTimeout(async () => {
const [version] = await sql`SELECT version()`;
resolve(Response.json(version));
}, 100);
});
},
},
});
路由优先级
路由匹配顺序按特异性依次为:
- 精确路由(
/users/all)
- 参数路由(
/users/:id)
- 通配符路由(
/users/*)
- 全局捕获(
/*)
Bun.serve({
routes: {
// 越具体的路由优先匹配
"/api/users/me": () => new Response("当前用户"),
"/api/users/:id": req => new Response(`用户 ${req.params.id}`),
"/api/*": () => new Response("API 捕获全部"),
"/*": () => new Response("全局捕获全部"),
},
});
类型安全的路由参数
TypeScript 会在字符串字面量传参时解析路由参数,从而使编辑器在访问 request.params 时提供自动补全。
index.tsimport type { BunRequest } from "bun";
Bun.serve({
routes: {
// 当以字符串字面量传入时,TypeScript 知道 params 的结构
"/orgs/:orgId/repos/:repoId": req => {
const { orgId, repoId } = req.params;
return Response.json({ orgId, repoId });
},
"/orgs/:orgId/repos/:repoId/settings": (
// 可选:可以显式为 BunRequest 传入类型参数:
req: BunRequest<"/orgs/:orgId/repos/:repoId/settings">,
) => {
const { orgId, repoId } = req.params;
return Response.json({ orgId, repoId });
},
},
});
百分号编码的路由参数值会自动解码,支持 Unicode 字符。无效的 unicode 会被替换成 Unicode 替代字符 &0xFFFD;。
静态响应
路由也可以是 Response 对象(无处理函数)。Bun.serve() 针对零分配调度做了优化——非常适合健康检查、重定向和固定内容:
Bun.serve({
routes: {
// 健康检查
"/health": new Response("OK"),
"/ready": new Response("准备就绪", {
headers: {
// 传递自定义头部
"X-Ready": "1",
},
}),
// 重定向
"/blog": Response.redirect("https://bun.com/blog"),
// API 响应
"/api/config": Response.json({
version: "1.0.0",
env: "production",
}),
},
});
静态响应在初始化后不分配额外内存。相比手动返回 Response 对象,通常能提升至少 15% 的性能。
静态路由响应会在服务器对象生命周期内缓存。若要重新加载静态路由,可调用 server.reload(options)。
文件响应与静态响应的区别
在路由中提供文件时,行为因缓冲文件内容还是直接传输而异:
Bun.serve({
routes: {
// 静态路由 — 内容在启动时缓冲到内存
"/logo.png": new Response(await Bun.file("./logo.png").bytes()),
// 文件路由 — 每次请求从文件系统读取内容
"/download.zip": new Response(Bun.file("./download.zip")),
},
});
静态路由 (new Response(await file.bytes())) 会在启动时将内容缓冲至内存:
- 请求时无文件系统 I/O — 内容完全从内存服务
- 支持 ETag — 自动生成与验证缓存的 ETag
- 支持 If-None-Match — 客户端 ETag 匹配时返回
304 Not Modified
- 无 404 处理 — 缺失文件在启动时报错,不在运行时 404
- 内存占用 — 文件内容全量存储于 RAM
- 适合用于:小型静态资源、API 响应、频繁访问的文件
文件路由 (new Response(Bun.file(path))) 每次请求从文件系统读取:
- 每次请求都会执行文件系统读取,检查文件存在并读取内容
- 内置 404 处理 — 若文件不存在或变得不可访问返回
404 Not Found
- 支持 Last-Modified — 基于文件修改时间处理
If-Modified-Since 头
- 支持 If-Modified-Since — 缓存有效时返回
304 Not Modified
- 支持 范围请求 — 自动处理部分内容请求,返回
Content-Range 头
- 支持流传输 — 使用带背压处理的缓冲读取器,实现高效内存使用
- 内存高效 — 只缓冲传输时的小块数据,不缓存整个文件
- 适合用于:大文件、动态内容、用户上传、频繁变更的文件
流式传输文件
要流式传输文件,返回一个以 BunFile 对象作为 body 的 Response。
Bun.serve({
fetch(req) {
return new Response(Bun.file("./hello.txt"));
},
});
⚡️ 速度 — Bun 会在可能的情况下自动使用 sendfile(2) 系统调用,
在内核级实现零拷贝文件传输—这是发送文件最快的方式。
你可以使用 Bun.file 对象的 slice(start, end) 方法发送文件的部分内容。此方法会自动为 Response 设置 Content-Range 和 Content-Length 头部。
Bun.serve({
fetch(req) {
// 解析 `Range` 头部
const [start = 0, end = Infinity] = req.headers
.get("Range") // Range: bytes=0-100
.split("=") // ["Range: bytes", "0-100"]
.at(-1) // "0-100"
.split("-") // ["0", "100"]
.map(Number); // [0, 100]
// 返回文件的片段
const bigFile = Bun.file("./big-video.mp4");
return new Response(bigFile.slice(start, end));
},
});
fetch 请求处理器
fetch 处理器用于处理未被任一路由匹配的入站请求。它接收一个 Request 对象,返回一个 Response 或 Promise<Response>。
Bun.serve({
fetch(req) {
const url = new URL(req.url);
if (url.pathname === "/") return new Response("首页!");
if (url.pathname === "/blog") return new Response("博客!");
return new Response("404!");
},
});
fetch 处理器支持 async/await:
import { sleep, serve } from "bun";
serve({
async fetch(req) {
const start = performance.now();
await sleep(10);
const end = performance.now();
return new Response(`睡眠了 ${end - start} 毫秒`);
},
});
也支持基于 Promise 的响应:
Bun.serve({
fetch(req) {
// 将请求转发到另一个服务器
return fetch("https://example.com");
},
});
你还可以从 fetch 处理器访问 Server 对象。它是传递给 fetch 函数的第二个参数。
// `server` 作为第二个参数传递给 `fetch`。
const server = Bun.serve({
fetch(req, server) {
const ip = server.requestIP(req);
return new Response(`您的 IP 是 ${ip.address}`);
},
});