JS读取Cookie时怎么处理中文乱码和特殊字符

作者:微光

时间:2026-10-30

浏览:530

深入解析在 JavaScript 中读取与解析 Cookie 时出现中文乱码和特殊字符冲突的底层成因,提供标准化 encodeURIComponent 与 decodeURIComponent 编码方案、异常容错解析流水线以及生产级避坑指南。

文章目录
JavaScript 读取 Cookie 时遇到中文乱码和特殊字符解析异常,其根本症结在于 Cookie 规范(RFC 6265)仅原生支持 ASCII 字符集,且分号(;)、等号(=)、空格等符号属于语法层面的保留分隔符。彻底解决该问题的标准化路径是:写入时使用 encodeURIComponent() 对键和值进行对等的百分比编码;读取时先按分号与首个等号安全拆分,再经由 decodeURIComponent() 搭配 try...catch 容错机制完成解码还原。

一、为什么 Cookie 会出现乱码与解析中断?

在前端开发中,直接通过 document.cookie = "username=张三" 写入中文,随后在控制台或业务逻辑中读取 document.cookie 时,开发者经常会看到诸如 username=%E5%BC%A0... 或者 username=ç®¡çђ†å‘˜ 这样的乱码与异常值。更严重的是,若 Cookie 的值中包含逗号、分号或等号,整条 Cookie 的结构往往会被强行腰斩,导致解析出的键值对完全错乱。

要理解这一现象,首先必须明确 Cookie 协议的底层限制:

  • 字符集硬性约束(RFC 6265 标准):HTTP Cookie 规范明确规定,Cookie 的 cookie-name 与 cookie-value 仅允许使用范围在 0x21 到 0x7E 之间的可见 US-ASCII 字符,且排除了控制字符、空格以及特定语法分隔符。
  • 中文字符的字节编码超标:一个汉字在 UTF-8 编码下占用 3 个字节(例如“张”对应 E5 BC A0)。因为这些字节码的数值远远超出了标准 ASCII 的取值区间(0~127),若浏览器或服务端 HTTP 传输头强制以 Latin-1(ISO-8859-1)进行单字节映射转译,就会立即产生不可读的乱码。
  • 核心保留分隔符冲突:在 document.cookie 返回的原始字符串中,不同 Cookie 之间使用 ; (分号加空格)隔离,键与值之间使用 =(等号)隔离。如果存入的值含有原生分号,解析器会将该值错误拆解为多条独立的 Cookie;如果存入的值含有等号(如 Base64 填充符 ==),简单的字符串分割就会把真实内容截断。
JS读取Cookie时怎么处理中文乱码和特殊字符
图 1:Cookie 底层字符规范与中文/特殊字符冲突机制

二、转码函数选型:为什么必须是 encodeURIComponent?

在历史遗留的前端代码或旧教程中,开发者常常能看到 escape() 或 encodeURI() 的使用记录。但在 Cookie 读写场景下,这两个函数均存在严重的缺陷甚至安全隐患。

编码函数 对中文字符的支持 对 Cookie 关键分隔符(; = ,)的处理 在 Cookie 场景的结论
escape() 编码为 %uXXXX 格式,非 UTF-8 标准 不转义 @ * _ + - . /,对部分符号转义不可靠 已废弃 严禁在新项目中使用,服务端几乎无法常规解析。
encodeURI() 完整转换为 UTF-8 百分比编码 完全不转义 ; , / ? : @ & = + $ # 不可用 保留了分号和等号,无法解决 Cookie 语法结构被破坏的问题。
encodeURIComponent() 完整转换为 UTF-8 百分比编码 严格转义 除了 A-Z a-z 0-9 - _ . ! ~ * ' ( ) 之外的一切符号 官方标准推荐 将中文字符、分号、等号完全转化为合规 ASCII,保障结构稳健。
JS读取Cookie时怎么处理中文乱码和特殊字符
图 2:escape、encodeURI 与 encodeURIComponent 对比决策矩阵

三、标准读取与解析步骤(带异常防御机制)

在实际项目中读取 Cookie,不仅需要使用 decodeURIComponent,还必须预防三个常见的边缘崩溃点:

  1. 空格与格式干扰:各浏览器返回的 document.cookie 键值对之间通常由 ; (分号+空格)分隔,但不能假设每个分号后必定有单个空格,必须执行 trim()。
  2. 值本身包含等号:例如加密后的密文、Base64 字符串(如 eyJ...==)中包含 =。如果简单调用 item.split('='),数组会被拆解为三段以上,造成值丢失。正确做法是只按第一个等号出现的位置切分。
  3. 非法的百分比序列导致 URIError 崩溃:如果页面中存在历史残留的未转义 Cookie、或者值中原本就有单独的 %(例如 discount=50%),直接执行 decodeURIComponent("50%") 会立即抛出未捕获的 URIError: URI malformed,从而导致整个页面的 JS 执行中断。因此,解码操作必须置于 try...catch 中。
JS读取Cookie时怎么处理中文乱码和特殊字符
图 3:JS 读取与解析 Cookie 健壮流水线(四步法)

1. 健壮的单个 Cookie 读取函数封装

基于上述四步逻辑,针对通过特定 name 读取单个 Cookie 的需求,可以实现如下高韧性封装:

/**
 * 健壮读取单个 Cookie 值(支持中文及特殊符号)
 * @param {string} name - Cookie 的键名
 * @returns {string|null} 解码后的字符串,未匹配则返回 null
 */
function getCookie(name) {
  if (!name || typeof document === 'undefined' || !document.cookie) {
    return null;
  }

  // 必须对搜索的 Key 同样进行编码,保持匹配一致
  const targetKey = encodeURIComponent(name);
  const cookieList = document.cookie.split(';');

  for (let i = 0; i < cookieList.length; i++) {
    const item = cookieList[i].trim();
    if (!item) continue;

    const equalIndex = item.indexOf('=');
    let rawKey = '';
    let rawVal = '';

    if (equalIndex === -1) {
      rawKey = item;
      rawVal = '';
    } else {
      rawKey = item.slice(0, equalIndex);
      rawVal = item.slice(equalIndex + 1);
    }

    // 比较 Key 是否一致(考虑 Key 自身可能经过 decode 或 encode)
    if (rawKey === targetKey || safeDecode(rawKey) === name) {
      return safeDecode(rawVal);
    }
  }

  return null;
}

/**
 * 安全解码辅助函数,防御 URIError 崩溃
 * @param {string} str 
 * @returns {string}
 */
function safeDecode(str) {
  try {
    return decodeURIComponent(str);
  } catch (err) {
    // 捕获畸形 % 序列,优雅降级返回原值
    return str;
  }
}

2. 批量解析所有 Cookie 为对象的函数封装

当业务需要批量获取所有 Cookie 键值对映射表时,采用一次性完整扫描解析:

/**
 * 解析所有 Cookie 为纯对象字典
 * @returns {Record}
 */
function parseCookies() {
  const result = {};
  if (typeof document === 'undefined' || !document.cookie) {
    return result;
  }

  const items = document.cookie.split(';');
  for (let i = 0; i < items.length; i++) {
    const item = items[i].trim();
    if (!item) continue;

    const equalIndex = item.indexOf('=');
    if (equalIndex === -1) {
      result[safeDecode(item)] = '';
    } else {
      const key = safeDecode(item.slice(0, equalIndex));
      const value = safeDecode(item.slice(equalIndex + 1));
      result[key] = value;
    }
  }

  return result;
}

四、配套写入规范:对称转码是根除乱码的前提

“读取无乱码”的前提是“写入有规范”。如果在写入端直接将未经编码的字符串强塞入 document.cookie,那么读取端无论怎么优化都只能被迫做“猜码”或“残缺容错”。

因此,在写入端必须同步配备规范的 setCookie 工具函数,确保成对编码:

/**
 * 规范写入 Cookie(自动执行 URIComponent 编码)
 * @param {string} name 键名
 * @param {string} value 键值(支持任意中文及特殊字符)
 * @param {number} [days=7] 有效天数
 * @param {string} [path='/'] 作用路径
 */
function setCookie(name, value, days = 7, path = '/') {
  const expiresDate = new Date(Date.now() + days * 86400000).toUTCString();
  const encodedKey = encodeURIComponent(name);
  const encodedVal = encodeURIComponent(value);

  document.cookie = `${encodedKey}=${encodedVal}; expires=${expiresDate}; path=${path}; SameSite=Lax`;
}

注意事项:JSON 复杂对象的存储陷阱

如果要将对象(如 { nickname: "小明", role: "管理员,VIP" })存入 Cookie:

  1. 必须先调用 JSON.stringify(obj) 转为字符串。
  2. 紧接着必须调用 encodeURIComponent(jsonString)。因为 JSON 中的引号、冒号、逗号均可能对 Cookie 属性或后端中间件解析造成干扰。
  3. 读取时逆向执行:JSON.parse(decodeURIComponent(val)),同样置于 try...catch 中防崩。

五、全生命周期核心规则与避坑指南

在实际生产环境中,Cookie 的读写往往涉及跨语言服务协同(如 Node.js、Java Spring、Python Django、Go Gin)以及复杂的历史遗留数据。以下是必须牢记的防御性设计规则:

JS读取Cookie时怎么处理中文乱码和特殊字符
图 4:JS Cookie 字符处理全生命周期核心规则与防御规范

六、总结与速查清单

回到文章的核心问题:JS读取Cookie时怎么处理中文乱码和特殊字符?

答案可以凝练为一个公式化的落地步骤:

  • 写:document.cookie = `${encodeURIComponent(k)}=${encodeURIComponent(v)}; path=/`
  • 切:拆分 ; 并 trim(),以首个 = 区分键与值;
  • 读:使用 safeDecode(rawVal)(封装了 decodeURIComponent 与 try...catch)安全恢复原始字符。

遵循这一套标准范式,不仅能杜绝中文乱码与特殊字符截断,更能让前端应用在面对不可控的脏数据或跨域历史 Cookie 时保持 100% 的高可用与防崩溃能力。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章