JavaScript 教學:DOM 與瀏覽器 API ── Cookie 操作
簡介
在 Web 開發中,Cookie 是最早且最常被使用的客戶端儲存機制之一。它允許伺服器在使用者的瀏覽器上保存小量資料,常見的用途包括:
- 會話管理(例如登入狀態、購物車內容)
- 使用者偏好設定(語系、主題顏色)
- 追蹤與分析(第三方廣告、流量統計)
雖然近年來 localStorage、sessionStorage 與 IndexedDB 逐漸流行,Cookie 仍不可或缺,尤其在 跨域請求、HTTP Only、Secure 等安全需求上扮演關鍵角色。因此,掌握 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 攻擊,可設定 Strict、Lax、None(需搭配 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(含 HttpOnly 與 Secure)
說明:
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=None 與 Secure 在跨站請求中傳遞 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,導致登入失效或追蹤失敗 | 依需求選擇 Lax、Strict 或 None,若使用 None 必須加 Secure |
| 過期時間使用本地時區 | 不同使用者時區造成失效時間不一致 | 建議使用 max-age(秒)或 UTC expires |
| Cookie 大小超過限制 (約 4KB) | 部分 Cookie 被截斷,導致資料遺失 | 把大量資料搬到 localStorage,只保留必要的辨識鍵 |
在 HTTPS 網站使用 Secure 卻仍以 HTTP 測試 |
Cookie 不會被寫入 | 確保測試環境使用 HTTPS(可利用自簽憑證) |
| 在同一網域不同子域同名 Cookie | 讀取時不確定是哪一個子域的值 | 使用 domain 屬性明確區分,或在名稱上加前綴 |
其他最佳實踐
- 最小化 Cookie 數量與大小:僅存放必要的識別碼(如 Session ID),其餘資訊移至
localStorage或伺服器端。 - 設定
HttpOnly與Secure:對於敏感資訊(認證、金流)必須使用這兩個屬性,防止 XSS 與中間人攻擊。 - 使用
SameSite防止 CSRF:除非真的需要跨站請求,否則避免使用SameSite=None。 - 定期清理過期或不再使用的 Cookie:可在使用者登出或服務更新時主動刪除。
- 遵守隱私法規(GDPR、CCPA):在收集 Cookie 前取得使用者同意,並提供「拒絕」或「刪除」選項。
實際應用場景
| 場景 | 為何使用 Cookie | 範例實作 |
|---|---|---|
| 使用者登入 | 需要在每次 HTTP 請求時自動帶上 Session ID,且不暴露於 JavaScript | 伺服器設定 HttpOnly; Secure; SameSite=Strict 的 sessionId |
| 語系切換 | 讓使用者在不同頁面、重新整理後仍保持選擇的語系 | 前端 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 時的首要考量:務必加上
HttpOnly、Secure、SameSite,並遵守隱私法規。 - 最佳實踐 包括限制大小、使用
max-age、明確設定path/domain、以及在不需要時主動清除。
掌握上述概念與技巧後,你就能在任何 Web 專案中,安全且有效率地運用 Cookie,提升使用者體驗與系統安全性。祝你寫程式快快樂樂,Cookie 用得更得心應手! 🚀