Bun 网络请求 #
概述 #
Bun 内置了 Web 标准的 fetch API 和 WebSocket 支持,无需安装 node-fetch 或 ws 等库即可进行网络请求和实时通信。
fetch API #
基本用法 #
typescript
// GET 请求
const response = await fetch("https://api.example.com/data");
const data = await response.json();
console.log(data);
// 获取文本
const text = await response.text();
// 获取 ArrayBuffer
const buffer = await response.arrayBuffer();
// 获取 Blob
const blob = await response.blob();
请求配置 #
typescript
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer token123",
},
body: JSON.stringify({
name: "Bun",
email: "bun@example.com",
}),
});
const user = await response.json();
console.log(user);
处理响应 #
typescript
const response = await fetch("https://api.example.com/data");
// 状态码
console.log(response.status); // 200
console.log(response.ok); // true
console.log(response.statusText); // "OK"
// 响应头
console.log(response.headers.get("content-type"));
console.log([...response.headers]);
// 读取内容
const json = await response.json();
const text = await response.text();
const buffer = await response.arrayBuffer();
const blob = await response.blob();
错误处理 #
typescript
try {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log(data);
} catch (error) {
if (error instanceof TypeError) {
console.error("Network error:", error.message);
} else {
console.error("Error:", error);
}
}
超时控制 #
typescript
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 5000);
try {
const response = await fetch("https://api.example.com/data", {
signal: controller.signal,
});
const data = await response.json();
console.log(data);
} catch (error) {
if (error.name === "AbortError") {
console.error("Request timed out");
}
} finally {
clearTimeout(timeout);
}
取消请求 #
typescript
const controller = new AbortController();
// 发起请求
const fetchPromise = fetch("https://api.example.com/data", {
signal: controller.signal,
});
// 取消请求
controller.abort();
try {
const response = await fetchPromise;
} catch (error) {
if (error.name === "AbortError") {
console.log("Request was cancelled");
}
}
Request 对象 #
创建 Request #
typescript
const request = new Request("https://api.example.com/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Bun" }),
});
const response = await fetch(request);
Request 属性 #
typescript
const request = new Request("https://api.example.com/data?q=test", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ key: "value" }),
});
console.log(request.url); // 完整 URL
console.log(request.method); // "POST"
console.log(request.headers); // Headers 对象
console.log(request.body); // ReadableStream
// 读取 body
const body = await request.json();
console.log(body);
克隆 Request #
typescript
const request = new Request("https://api.example.com/data", {
body: JSON.stringify({ key: "value" }),
});
// 克隆请求
const clonedRequest = request.clone();
Response 对象 #
创建 Response #
typescript
// 基本响应
const response = new Response("Hello, World!", {
status: 200,
headers: { "Content-Type": "text/plain" },
});
// JSON 响应
const jsonResponse = Response.json({ message: "Hello" });
// 重定向
const redirectResponse = Response.redirect("https://example.com", 302);
// 错误响应
const errorResponse = Response.error();
Response 方法 #
typescript
const response = new Response("Hello");
// 克隆
const cloned = response.clone();
// 读取内容
const text = await response.text();
const json = await response.json();
const buffer = await response.arrayBuffer();
const blob = await response.blob();
Headers 对象 #
创建 Headers #
typescript
// 从对象创建
const headers = new Headers({
"Content-Type": "application/json",
"Authorization": "Bearer token",
});
// 添加头部
headers.set("X-Custom", "value");
headers.append("X-Custom", "another");
// 获取头部
console.log(headers.get("Content-Type"));
console.log(headers.get("X-Custom")); // "value, another"
// 检查存在
console.log(headers.has("Authorization"));
// 删除头部
headers.delete("X-Custom");
// 遍历
for (const [key, value] of headers) {
console.log(`${key}: ${value}`);
}
常见请求场景 #
GET 请求 #
typescript
// 简单 GET
const data = await fetch("https://api.example.com/data").then(r => r.json());
// 带查询参数
const url = new URL("https://api.example.com/search");
url.searchParams.set("q", "bun");
url.searchParams.set("limit", "10");
const results = await fetch(url).then(r => r.json());
POST 请求 #
typescript
// JSON 数据
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: "Bun", email: "bun@example.com" }),
});
// 表单数据
const formData = new FormData();
formData.append("name", "Bun");
formData.append("file", new Blob(["content"]), "file.txt");
const response = await fetch("https://api.example.com/upload", {
method: "POST",
body: formData,
});
// URL 编码
const params = new URLSearchParams();
params.append("name", "Bun");
params.append("email", "bun@example.com");
const response = await fetch("https://api.example.com/users", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
});
文件上传 #
typescript
// 上传文件
const file = Bun.file("./document.pdf");
const response = await fetch("https://api.example.com/upload", {
method: "POST",
body: file,
});
// 上传多个文件
const formData = new FormData();
formData.append("file1", Bun.file("./file1.txt"));
formData.append("file2", Bun.file("./file2.txt"));
const response = await fetch("https://api.example.com/upload", {
method: "POST",
body: formData,
});
文件下载 #
typescript
// 下载文件
const response = await fetch("https://example.com/file.pdf");
const blob = await response.blob();
// 保存到本地
await Bun.write("./downloaded.pdf", blob);
// 流式下载大文件
const response = await fetch("https://example.com/large-file.zip");
const stream = response.body;
if (stream) {
const file = Bun.file("./large-file.zip");
await Bun.write("./large-file.zip", stream);
}
认证请求 #
typescript
// Basic Auth
const credentials = btoa("username:password");
const response = await fetch("https://api.example.com/protected", {
headers: {
"Authorization": `Basic ${credentials}`,
},
});
// Bearer Token
const response = await fetch("https://api.example.com/protected", {
headers: {
"Authorization": "Bearer your-token-here",
},
});
// API Key
const response = await fetch("https://api.example.com/data", {
headers: {
"X-API-Key": "your-api-key",
},
});
Cookie 处理 #
typescript
// 发送 Cookie
const response = await fetch("https://api.example.com/data", {
credentials: "include", // 包含 Cookie
headers: {
"Cookie": "session=abc123",
},
});
// 获取 Set-Cookie
const setCookie = response.headers.get("set-cookie");
WebSocket #
客户端 WebSocket #
typescript
const ws = new WebSocket("wss://example.com/socket");
ws.onopen = () => {
console.log("Connected");
ws.send("Hello, Server!");
};
ws.onmessage = (event) => {
console.log("Received:", event.data);
};
ws.onerror = (error) => {
console.error("Error:", error);
};
ws.onclose = (event) => {
console.log("Disconnected", event.code, event.reason);
};
// 发送消息
ws.send("Hello");
ws.send(JSON.stringify({ type: "ping" }));
// 发送二进制数据
const buffer = new Uint8Array([1, 2, 3, 4]);
ws.send(buffer);
// 关闭连接
ws.close(1000, "Goodbye");
WebSocket 连接选项 #
typescript
const ws = new WebSocket("wss://example.com/socket", {
headers: {
"Authorization": "Bearer token",
},
protocols: ["chat", "superchat"],
});
心跳保活 #
typescript
const ws = new WebSocket("wss://example.com/socket");
let pingInterval: Timer;
ws.onopen = () => {
pingInterval = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({ type: "ping" }));
}
}, 30000);
};
ws.onclose = () => {
clearInterval(pingInterval);
};
自动重连 #
typescript
class ReconnectingWebSocket {
private ws: WebSocket | null = null;
private url: string;
private reconnectAttempts = 0;
private maxReconnectAttempts = 5;
private reconnectDelay = 1000;
constructor(url: string) {
this.url = url;
this.connect();
}
private connect() {
this.ws = new WebSocket(this.url);
this.ws.onopen = () => {
console.log("Connected");
this.reconnectAttempts = 0;
};
this.ws.onclose = () => {
console.log("Disconnected");
this.reconnect();
};
this.ws.onerror = (error) => {
console.error("Error:", error);
};
}
private reconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = this.reconnectDelay * this.reconnectAttempts;
console.log(`Reconnecting in ${delay}ms...`);
setTimeout(() => this.connect(), delay);
}
}
send(data: string) {
this.ws?.send(data);
}
close() {
this.ws?.close();
}
}
HTTP 客户端封装 #
请求函数封装 #
typescript
interface RequestOptions extends RequestInit {
timeout?: number;
params?: Record<string, string>;
}
async function request<T>(
url: string,
options: RequestOptions = {}
): Promise<T> {
const { timeout = 30000, params, ...init } = options;
// 添加查询参数
if (params) {
const urlObj = new URL(url);
Object.entries(params).forEach(([key, value]) => {
urlObj.searchParams.set(key, value);
});
url = urlObj.toString();
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...init,
signal: controller.signal,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
} finally {
clearTimeout(timeoutId);
}
}
// 使用
const data = await request<{ id: number }>("https://api.example.com/data", {
params: { page: "1" },
});
API 客户端类 #
typescript
class APIClient {
private baseURL: string;
private headers: HeadersInit;
constructor(baseURL: string, headers: HeadersInit = {}) {
this.baseURL = baseURL;
this.headers = headers;
}
async get<T>(path: string, params?: Record<string, string>): Promise<T> {
const url = new URL(path, this.baseURL);
if (params) {
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
}
const response = await fetch(url, {
headers: this.headers,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async post<T>(path: string, body: unknown): Promise<T> {
const response = await fetch(new URL(path, this.baseURL), {
method: "POST",
headers: {
...this.headers,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async put<T>(path: string, body: unknown): Promise<T> {
const response = await fetch(new URL(path, this.baseURL), {
method: "PUT",
headers: {
...this.headers,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
async delete<T>(path: string): Promise<T> {
const response = await fetch(new URL(path, this.baseURL), {
method: "DELETE",
headers: this.headers,
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return response.json();
}
}
// 使用
const api = new APIClient("https://api.example.com", {
"Authorization": "Bearer token",
});
const users = await api.get<User[]>("/users");
const user = await api.post<User>("/users", { name: "Bun" });
下一步 #
现在你已经了解了 Bun 的网络请求功能,接下来学习 进程与子进程 深入了解 Bun 的进程管理。
最后更新:2026-03-29