H3 Cookie 工具

2026-10-30 17:48 更新

Cookie 工具一共八个函数,核心是四个读写 + 三个分块处理 + 一个批量校验。它们底层用 cookie-es,所以在 v2 里 splitCookiesString 这类旧工具已经不在 h3 里了(改用 cookie-es 的 splitSetCookieString)。

四个基础操作

import { H3, getCookie, setCookie, deleteCookie, parseCookies } from "h3";

const app = new H3()
  .post("/login", (event) => {
    // 写:只往 event.res 追加 Set-Cookie,本身不产生响应
    setCookie(event, "token", "abc123", {
      httpOnly: true, // JS 读不到,防 XSS 窃取
      secure: true, // 只在 HTTPS 下发送
      sameSite: "lax", // 防 CSRF 的基础设置
      path: "/",
      maxAge: 60 * 60 * 24 * 7,
    });
    return { ok: true };
  })
  .get("/me", (event) => {
    // 读单个:不存在返回 undefined
    const token = getCookie(event, "token");

    // 一次读全部,值是字符串;同名多值会是数组
    const all = parseCookies(event);
    return { token, count: Object.keys(all).length };
  })
  .post("/logout", (event) => {
    // 删:实际是设一个立即过期的同名 cookie
    deleteCookie(event, "token", { path: "/" });
    return { ok: true };
  });

三条实践规则:

  1. path 要一致。写入时用了 path: "/admin",删除时也必须写同样的 path,否则删不掉——浏览器按 (name, domain, path) 三元组匹配 cookie。
  2. 多个 Set-Cookie 不要用 headers.get 读。标准 Headers 会把它们合并成一个字符串,v2 提供 event.res.headers.getSetCookie() 返回数组(3.4 讲过这个 API)。
  3. 敏感内容不要明文放 cookie。cookie 在客户端可读、可篡改,需要签名或加密就走会话(6.6),或者直接用社区库 unjwt(6.10)。

超过 4KB 自动分块

浏览器对单个 cookie 有容量上限(约 4KB),存大一点的 JSON 就会静默丢失。H3 提供三个分块版本:

import { H3, setChunkedCookie, getChunkedCookie, deleteChunkedCookie } from "h3";

const app = new H3()
  .post("/save", (event) => {
    // 值短就写普通 cookie;超过分块阈值(默认 4000 字符)会自动拆成多个
    setChunkedCookie(event, "prefs", JSON.stringify({ theme: "dark", langs: ["zh", "en"] }));
    return { ok: true };
  })
  .get("/load", (event) => {
    // 读取时自动把所有分片拼回原值,不需要你知道拆成了几块
    const raw = getChunkedCookie(event, "prefs");
    return { prefs: raw ? JSON.parse(raw) : null };
  })
  .post("/clear", (event) => {
    // 删除会连同所有分片一起清掉
    deleteChunkedCookie(event, "prefs");
    return { ok: true };
  });

实现细节值得知道,排查问题时有用:

细节 说明
阈值 默认每片 4000 字符,可用 chunkMaxLength 调整
主 cookie 存一个以 __chunked__ 开头的计数标记,不存数据本身
分片 cookie 按序号命名的独立 cookie,读取时按计数逐个取
只有一个分片时 退化为普通 cookie,不写标记
单个字符都放不下 直接抛错,而不是写出坏数据

所以分块 cookie 在浏览器 DevTools 里会显示成好几条,看起来像重复写入,其实是设计如此。

批量校验:getValidatedCookies

import { H3, getValidatedCookies } from "h3";
import { z } from "zod";

const app = new H3().get("/settings", async (event) => {
  const cookies = await getValidatedCookies(
    event,
    z.object({ theme: z.enum(["light", "dark"]) }),
    // 校验失败时自定义错误,默认抛 400
    { onError: ({ issues }) => ({ statusText: "cookie 不合法", message: String(issues) }) },
  );
  return cookies;
});

它和 readValidatedBody、getValidatedQuery 是同一套校验机制,只是作用对象换成了全部 cookie。

排查表

现象 最可能原因 处理
删不掉 cookie 写入与删除的 path/domain 不一致 两处保持完全相同
大 JSON 存进 cookie 后读不到 超过 4KB 被浏览器丢弃 改用 setChunkedCookie
线上 HTTPS 下 cookie 不发送 漏了 secure,或反向代理下协议判断错误 检查 secure 与代理解析
只读到最后一个 Set-Cookie 用了 headers.get 改 headers.getSetCookie()
getChunkedCookie 返回 undefined 分片缺失(用户清了部分 cookie) 按整体失效处理,重新写入
服务端拿到的值带引号 值被编码,读取端没解码 统一用 getCookie 读,或显式 decode

延伸阅读

  • Cookie 与会话的配合方式:见 6.6 安全工具
  • Set-Cookie 在 v2 里的读取方式:见 8.1 v1 到 v2 迁移:核心变更
  • 一个完整的中小型会话实现:见 7.3 会话基础
以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号