本文 AI 產出,尚未審核

JavaScript 教學:DOM 與瀏覽器 API ── Cookie 操作


簡介

在 Web 開發中,Cookie 是最早且最常被使用的客戶端儲存機制之一。它允許伺服器在使用者的瀏覽器上保存小量資料,常見的用途包括:

  1. 會話管理(例如登入狀態、購物車內容)
  2. 使用者偏好設定(語系、主題顏色)
  3. 追蹤與分析(第三方廣告、流量統計)

雖然近年來 localStoragesessionStorageIndexedDB 逐漸流行,Cookie 仍不可或缺,尤其在 跨域請求HTTP OnlySecure 等安全需求上扮演關鍵角色。因此,掌握 Cookie 的讀寫、屬性設定與最佳實踐,是每位前端開發者的基本功。

本篇文章將以 DOM 與瀏覽器 API 為切入點,深入探討 Cookie 的操作方式,提供實用範例、常見陷阱與最佳實踐,讓你能在真實專案中自信地使用 Cookie。


核心概念

1. Cookie 的結構與基本屬性

一顆 Cookie 在瀏覽器中以 name=value 的字串形式儲存,後面可接多個屬性(attribute),常見屬性說明如下:

屬性 說明 範例
expires 設定 Cookie 的失效時間(GMT 字串),若未設定則為「會話 Cookie」 expires=Wed, 09 Jun 2025 10:18:14 GMT
max-age 以秒為單位的存活時間,優先於 expires max-age=3600
path 指定 Cookie 作用的路徑,預設為當前路徑 path=/
domain 指定可接受 Cookie 的網域,支援子域名 domain=example.com
secure 僅在 HTTPS 連線時傳送 secure
HttpOnly JavaScript 無法透過 document.cookie 讀取,僅限 HTTP 請求使用 HttpOnly
SameSite 防止 CSRF 攻擊,可設定 StrictLaxNone(需搭配 Secure SameSite=Lax

小提醒:在設定 SameSite=None 時,必須同時加上 Secure,否則瀏覽器會直接拋棄 Cookie。


2. 讀寫 Cookie 的基本 API

在瀏覽器環境中,Cookie 只能透過 document.cookie 這個屬性存取。它的行為如下:

  • 寫入:將字串 name=value; [屬性] 指派給 document.cookie,瀏覽器會自動合併或覆寫同名的 Cookie。
  • 讀取document.cookie 會回傳所有可見 Cookie 的字串,格式為 name1=value1; name2=value2; …

注意document.cookie 僅支援 UTF-8,若要儲存中文或特殊字元,需要先 encodeURIComponent,讀取時再 decodeURIComponent


3. 常用的 Cookie 操作函式

為了避免每次都寫冗長的字串操作,我們通常會封裝三個常用函式:

/**
 * 設定 Cookie
 * @param {string} name   Cookie 名稱
 * @param {string} value  Cookie 值 (會自動 encode)
 * @param {Object} [options] 可選屬性 {expires, maxAge, path, domain, secure, sameSite}
 */
function setCookie(name, value, options = {}) {
  const encodedValue = encodeURIComponent(value);
  let cookieStr = `${name}=${encodedValue}`;

  if (options.expires) {
    // 支援 Date 物件或字串
    const expires = options.expires instanceof Date
      ? options.expires.toUTCString()
      : options.expires;
    cookieStr += `; expires=${expires}`;
  }

  if (options.maxAge) cookieStr += `; max-age=${options.maxAge}`;
  if (options.path) cookieStr += `; path=${options.path}`;
  if (options.domain) cookieStr += `; domain=${options.domain}`;
  if (options.secure) cookieStr += `; secure`;
  if (options.sameSite) cookieStr += `; samesite=${options.sameSite}`;

  document.cookie = cookieStr;
}

/**
 * 取得指定名稱的 Cookie
 * @param {string} name
 * @returns {string|null}
 */
function getCookie(name) {
  const match = document.cookie.match(
    new RegExp('(?:^|; )' + name.replace(/([.$?*|{}()\\[\\]\\/\\+^])/g, '\\$1') + '=([^;]*)')
  );
  return match ? decodeURIComponent(match[1]) : null;
}

/**
 * 刪除 Cookie(設定過期時間為過去)
 * @param {string} name
 * @param {Object} [options] 同 setCookie,需提供 path/domain 才能正確刪除
 */
function deleteCookie(name, options = {}) {
  setCookie(name, '', { ...options, expires: new Date(0) });
}

這三個函式已涵蓋 編碼/解碼屬性設定跨路徑刪除 等常見需求,使用上相當直觀。


4. 程式碼範例

以下提供 5 個實務範例,示範不同情境下的 Cookie 操作。

範例 1️⃣ 設定登入狀態 Cookie(含 HttpOnlySecure

說明HttpOnly 必須在伺服器端設定,前端無法直接加上。此範例示範伺服器回傳 Set-Cookie 時的寫法,前端則只負責讀取。

# 伺服器回傳 (Node.js Express 範例)
res.cookie('sessionId', 'abc123xyz', {
  httpOnly: true,   // 前端 JavaScript 無法讀取
  secure: true,     // 只在 HTTPS 傳送
  sameSite: 'Strict',
  maxAge: 24 * 60 * 60 * 1000 // 1 天
});

範例 2️⃣ 設定使用者偏好的主題顏色(可被 JavaScript 讀寫)

// 使用 setCookie 函式,存放於根路徑,7 天後過期
setCookie('theme', 'dark', {
  maxAge: 7 * 24 * 60 * 60, // 7 天
  path: '/',                 // 整個網站都可存取
  sameSite: 'Lax'
});

// 之後在任何頁面讀取
const theme = getCookie('theme') || 'light';
document.body.classList.add(`theme-${theme}`);

範例 3️⃣ 設定多語系偏好(含 expires 日期)

// 設定一個會在 2026 年 1 月 1 日過期的語系 Cookie
const expireDate = new Date('2026-01-01T00:00:00Z');
setCookie('lang', 'zh-TW', {
  expires: expireDate,
  path: '/',
  sameSite: 'Lax'
});

範例 4️⃣ 刪除特定路徑下的 Cookie

// 假設之前在 /admin 路徑下設定過 authToken
deleteCookie('authToken', { path: '/admin', domain: 'example.com' });

範例 5️⃣ 使用 SameSite=NoneSecure 在跨站請求中傳遞 Cookie

// 這裡示範在第三方 iframe 中設定可跨站使用的 Cookie
setCookie('thirdPartyId', '789xyz', {
  maxAge: 30 * 24 * 60 * 60, // 30 天
  path: '/',
  sameSite: 'None',          // 必須搭配 Secure
  secure: true
});

常見陷阱與最佳實踐

陷阱 可能的結果 解決方案 / 最佳實踐
未編碼中文或特殊字元 讀取時得到亂碼或截斷 使用 encodeURIComponent / decodeURIComponent
忘記設定 path 刪除或覆寫時只能在當前路徑生效,導致舊 Cookie 殘留 設定 path=/ 讓全站皆可存取或依需求明確指定
SameSite 設定錯誤 第三方請求不會帶上 Cookie,導致登入失效或追蹤失敗 依需求選擇 LaxStrictNone,若使用 None 必須加 Secure
過期時間使用本地時區 不同使用者時區造成失效時間不一致 建議使用 max-age(秒)或 UTC expires
Cookie 大小超過限制 (約 4KB) 部分 Cookie 被截斷,導致資料遺失 把大量資料搬到 localStorage,只保留必要的辨識鍵
在 HTTPS 網站使用 Secure 卻仍以 HTTP 測試 Cookie 不會被寫入 確保測試環境使用 HTTPS(可利用自簽憑證)
在同一網域不同子域同名 Cookie 讀取時不確定是哪一個子域的值 使用 domain 屬性明確區分,或在名稱上加前綴

其他最佳實踐

  1. 最小化 Cookie 數量與大小:僅存放必要的識別碼(如 Session ID),其餘資訊移至 localStorage 或伺服器端。
  2. 設定 HttpOnlySecure:對於敏感資訊(認證、金流)必須使用這兩個屬性,防止 XSS 與中間人攻擊。
  3. 使用 SameSite 防止 CSRF:除非真的需要跨站請求,否則避免使用 SameSite=None
  4. 定期清理過期或不再使用的 Cookie:可在使用者登出或服務更新時主動刪除。
  5. 遵守隱私法規(GDPR、CCPA):在收集 Cookie 前取得使用者同意,並提供「拒絕」或「刪除」選項。

實際應用場景

場景 為何使用 Cookie 範例實作
使用者登入 需要在每次 HTTP 請求時自動帶上 Session ID,且不暴露於 JavaScript 伺服器設定 HttpOnly; Secure; SameSite=StrictsessionId
語系切換 讓使用者在不同頁面、重新整理後仍保持選擇的語系 前端 setCookie('lang', 'en-US', { maxAge: 365*24*60*60 })
A/B 測試 依據使用者屬性分配不同實驗組,需在多個頁面保持一致 setCookie('experimentGroup', 'B', { path: '/', maxAge: 30*24*60*60 })
跨站第三方登入(OAuth) 第三方服務需要在回傳時寫入 Cookie,之後再由主站讀取 setCookie('oauth_state', state, { sameSite: 'None', secure: true })
電商購物車(未登入) 保存未結帳商品資訊,讓使用者下次回來仍能看到 setCookie('cart', JSON.stringify(cartItems), { maxAge: 7*24*60*60, path: '/' })

總結

  • Cookie 雖然是最古老的前端儲存機制,但在 會話管理、跨域請求與安全層面 仍扮演不可取代的角色。
  • 透過 document.cookie 搭配 封裝好的 setCookie / getCookie / deleteCookie 函式,我們可以輕鬆完成編碼、屬性設定與跨路徑刪除等工作。
  • 安全性 是使用 Cookie 時的首要考量:務必加上 HttpOnlySecureSameSite,並遵守隱私法規。
  • 最佳實踐 包括限制大小、使用 max-age、明確設定 path/domain、以及在不需要時主動清除。

掌握上述概念與技巧後,你就能在任何 Web 專案中,安全且有效率地運用 Cookie,提升使用者體驗與系統安全性。祝你寫程式快快樂樂,Cookie 用得更得心應手! 🚀