Cookie
使用 Bun 的原生 API 處理 HTTP Cookie
Bun 提供了兩個用於處理 HTTP Cookie 的原生 API:Bun.Cookie 和 Bun.CookieMap。它們可以解析、生成和操作 HTTP 請求與響應中的 Cookie。
CookieMap 類
Bun.CookieMap 是一個類似 Map 的 cookie 集合。它實現了 Iterable,因此可以與 for...of 迴圈和其他迭代方法一起使用。
// 建立空的 CookieMap
const cookies = new Bun.CookieMap();
// 從 cookie 字串建立
const cookies1 = new Bun.CookieMap("name=value; foo=bar");
// 從物件建立
const cookies2 = new Bun.CookieMap({
session: "abc123",
theme: "dark",
});
// 從名稱/值對陣列建立
const cookies3 = new Bun.CookieMap([
["session", "abc123"],
["theme", "dark"],
]);
在 HTTP 伺服器中使用
在 Bun 的 HTTP 伺服器中,請求物件(在 routes 中)的 cookies 屬性是 CookieMap 的一個例項:
const server = Bun.serve({
routes: {
"/": req => {
// 訪問請求中的 cookies
const cookies = req.cookies;
// 獲取指定名稱的 cookie
const sessionCookie = cookies.get("session");
if (sessionCookie != null) {
console.log(sessionCookie);
}
// 檢查是否存在某個 cookie
if (cookies.has("theme")) {
// ...
}
// 設定一個 cookie,這個操作會自動應用到響應中
cookies.set("visited", "true");
return new Response("Hello");
},
},
});
console.log("伺服器監聽地址: " + server.url);
方法
get(name: string): string | null
根據名稱獲取 cookie。如果不存在則傳回 null。
// 通過名稱獲取 cookie
const cookie = cookies.get("session");
if (cookie != null) {
console.log(cookie);
}
has(name: string): boolean
檢查是否存在指定名稱的 cookie。
// 檢查 cookie 是否存在
if (cookies.has("session")) {
// Cookie 存在
}
set(name: string, value: string, options?: CookieInit): void
set(options: CookieInit): void
set(cookie: Cookie): void
新增或更新一個 cookie。預設的 cookie 設定為 { path: "/", sameSite: "lax" }。
// 通過名稱和值設定
cookies.set("session", "abc123");
// 使用設定物件設定
cookies.set({
name: "theme",
value: "dark",
maxAge: 3600,
secure: true,
});
// 使用 Cookie 例項設定
const cookie = new Bun.Cookie("visited", "true");
cookies.set(cookie);
delete(name: string): void
delete(options: CookieStoreDeleteOptions): void
delete(name: string, options: Omit<CookieStoreDeleteOptions, "name">): void
從 map 中移除 cookie。應用到 Response 時,刪除操作會新增一個值為空字串且過期日期已過的 cookie。只有當域和路徑與建立該 cookie 時使用的域和路徑匹配時,瀏覽器才會刪除該 cookie。
// 用預設域和路徑通過名稱刪除
cookies.delete("session");
// 帶域和路徑選項刪除
cookies.delete({
name: "session",
domain: "example.com",
path: "/admin",
});
toJSON(): Record<string, string>
將 cookie map 轉換為可序列化的格式。
const json = cookies.toJSON();
toSetCookieHeaders(): string[]
傳回一個包含所有 cookie 變更對應的 Set-Cookie 標頭值的陣列。
將此方法用於 Bun.serve() 以外的 HTTP 伺服器。在 Bun.serve() 中,無需呼叫此方法:Bun 會自動將你對 req.cookies map 所做的任何更改應用到響應標頭中。
import { createServer } from "node:http";
import { CookieMap } from "bun";
const server = createServer((req, res) => {
const cookieHeader = req.headers.cookie || "";
const cookies = new CookieMap(cookieHeader);
cookies.set("view-count", Number(cookies.get("view-count") || "0") + 1);
cookies.delete("session");
res.writeHead(200, {
"Content-Type": "text/plain",
"Set-Cookie": cookies.toSetCookieHeaders(),
});
res.end(`Found ${cookies.size} cookies`);
});
server.listen(3000, () => {
console.log("伺服器執行在 http://localhost:3000/");
});
迭代
CookieMap 提供了多種迭代方法:
// 迭代 [name, cookie] 條目
for (const [name, value] of cookies) {
console.log(`${name}: ${value}`);
}
// 使用 entries()
for (const [name, value] of cookies.entries()) {
console.log(`${name}: ${value}`);
}
// 使用 keys()
for (const name of cookies.keys()) {
console.log(name);
}
// 使用 values()
for (const value of cookies.values()) {
console.log(value);
}
// 使用 forEach
cookies.forEach((value, name) => {
console.log(`${name}: ${value}`);
});
屬性
size: number
傳回 map 中 cookie 的數量。
console.log(cookies.size); // cookie 數量
Cookie 類
Bun.Cookie 表示一個 HTTP cookie,包括名稱、值以及屬性。
import { Cookie } from "bun";
// 建立基礎 cookie
const cookie = new Bun.Cookie("name", "value");
// 建立帶選項的 cookie
const secureSessionCookie = new Bun.Cookie("session", "abc123", {
domain: "example.com",
path: "/admin",
expires: new Date(Date.now() + 86400000), // 1 天后過期
httpOnly: true,
secure: true,
sameSite: "strict",
});
// 從 cookie 字串解析
const parsedCookie = new Bun.Cookie("name=value; Path=/; HttpOnly");
// 從設定物件建立
const objCookie = new Bun.Cookie({
name: "theme",
value: "dark",
maxAge: 3600,
secure: true,
});
建構函式
// 基礎建構函式,帶名稱和值
new Bun.Cookie(name: string, value: string);
// 帶名稱、值和選項的建構函式
new Bun.Cookie(name: string, value: string, options: CookieInit);
// 從 cookie 字串構造
new Bun.Cookie(cookieString: string);
// 從 cookie 物件構造
new Bun.Cookie(options: CookieInit);
屬性
cookie.name; // 字串 - Cookie 名稱
cookie.value; // 字串 - Cookie 值
cookie.domain; // 字串 | null - 域作用域(未指定時為 null)
cookie.path; // 字串 - URL 路徑作用域(預設為 "/")
cookie.expires; // Date | undefined - 過期日期
cookie.secure; // 布林值 - 要求使用 HTTPS
cookie.sameSite; // "strict" | "lax" | "none" - SameSite 設定
cookie.partitioned; // 布林值 - Cookie 是否已分割槽(CHIPS)
cookie.maxAge; // 數字 | undefined - 最大存活時間(秒)
cookie.httpOnly; // 布林值 - 只能通過 HTTP 訪問(不能通過 JavaScript 訪問)
方法
isExpired(): boolean
檢查 cookie 是否已過期。當同時設定了 maxAge 和 expires 時,按照 RFC 6265 的要求,以 maxAge 為準。
// 已過期 cookie(日期為過去)
const expiredCookie = new Bun.Cookie("name", "value", {
expires: new Date(Date.now() - 1000),
});
console.log(expiredCookie.isExpired()); // true
// 有效 cookie(使用 maxAge 而非 expires)
const validCookie = new Bun.Cookie("name", "value", {
maxAge: 3600, // 1 小時(秒)
});
console.log(validCookie.isExpired()); // false
// 非正數的 maxAge 會使 cookie 立即過期
const deletedCookie = new Bun.Cookie("name", "value", { maxAge: 0 });
console.log(deletedCookie.isExpired()); // true
// 會話 cookie(無過期時間)
const sessionCookie = new Bun.Cookie("name", "value");
console.log(sessionCookie.isExpired()); // false
serialize(): string
toString(): string
傳回適用於 Set-Cookie 頭的字串格式。
const cookie = new Bun.Cookie("session", "abc123", {
domain: "example.com",
path: "/admin",
expires: new Date(Date.now() + 86400000),
secure: true,
httpOnly: true,
sameSite: "strict",
});
console.log(cookie.serialize());
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Wed, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=Strict"
console.log(cookie.toString());
// => "session=abc123; Domain=example.com; Path=/admin; Expires=Wed, 19 Mar 2025 15:03:26 GMT; Secure; HttpOnly; SameSite=Strict"
toJSON(): CookieInit
將 cookie 轉換為適合 JSON 序列化的普通物件。
const cookie = new Bun.Cookie("session", "abc123", {
secure: true,
httpOnly: true,
});
const json = cookie.toJSON();
// => {
// name: "session",
// value: "abc123",
// path: "/",
// secure: true,
// httpOnly: true,
// sameSite: "lax",
// partitioned: false
// }
// 可直接用於 JSON.stringify
const jsonString = JSON.stringify(cookie);
靜態方法
Cookie.parse(cookieString: string): Cookie
將 cookie 字串解析為 Cookie 例項。
const cookie = Bun.Cookie.parse("name=value; Path=/; Secure; SameSite=Lax");
console.log(cookie.name); // "name"
console.log(cookie.value); // "value"
console.log(cookie.path); // "/"
console.log(cookie.secure); // true
console.log(cookie.sameSite); // "lax"
Cookie.from(name: string, value: string, options?: CookieInit): Cookie
用於建立 cookie 的工廠方法。
const cookie = Bun.Cookie.from("session", "abc123", {
httpOnly: true,
secure: true,
maxAge: 3600,
});
型別定義
interface CookieInit {
name?: string;
value?: string;
domain?: string;
/** 預設為 '/'。若想讓瀏覽器自行設定路徑,使用空字串。 */
path?: string;
expires?: number | Date | string;
secure?: boolean;
/** 預設為 `lax`。 */
sameSite?: CookieSameSite;
httpOnly?: boolean;
partitioned?: boolean;
maxAge?: number;
}
interface CookieStoreDeleteOptions {
name: string;
domain?: string | null;
path?: string;
}
interface CookieStoreGetOptions {
name?: string;
url?: string;
}
type CookieSameSite = "strict" | "lax" | "none";
class Cookie {
constructor(name: string, value: string, options?: CookieInit);
constructor(cookieString: string);
constructor(cookieObject?: CookieInit);
readonly name: string;
value: string;
domain: string | null;
path: string;
expires?: Date;
secure: boolean;
sameSite: CookieSameSite;
partitioned: boolean;
maxAge?: number;
httpOnly: boolean;
isExpired(): boolean;
serialize(): string;
toString(): string;
toJSON(): CookieInit;
static parse(cookieString: string): Cookie;
static from(name: string, value: string, options?: CookieInit): Cookie;
}
class CookieMap implements Iterable<[string, string]> {
constructor(init?: string[][] | Record<string, string> | string);
get(name: string): string | null;
toSetCookieHeaders(): string[];
has(name: string): boolean;
set(name: string, value: string, options?: CookieInit): void;
set(options: CookieInit): void;
delete(name: string): void;
delete(options: CookieStoreDeleteOptions): void;
delete(name: string, options: Omit<CookieStoreDeleteOptions, "name">): void;
toJSON(): Record<string, string>;
readonly size: number;
entries(): IterableIterator<[string, string]>;
keys(): IterableIterator<string>;
values(): IterableIterator<string>;
forEach(callback: (value: string, key: string, map: CookieMap) => void): void;
[Symbol.iterator](): IterableIterator<[string, string]>;
}