codecamp

H3 会话基础

会话(session)是用 cookie 记住用户状态的标准做法:登录态、语言偏好、购物车,都靠它在多次请求之间保持。H3 把会话封装成一组工具,其中你 90% 的时间只用 useSession。

工具家族

  • useSession(event, opts):初始化(或取出)会话,返回一个可操作的包装对象。最常用。
  • getSession(event, opts):只取当前会话,不创建新的。
  • updateSession(event, opts, data):更新会话数据。
  • clearSession(event, opts):清空当前会话。

useSession 在底层就是「没有就创建、有就取出」的 getSession + 写回逻辑,所以下面所有示例都用它。

初始化一个会话

import { useSession } from "h3";

app.use(async (event) => {
  // password 是封印每个会话 cookie 的密钥,必须从环境变量加载(见下文安全警告)
  const session = await useSession(event, {
    password: process.env.SESSION_PASSWORD ?? "[演示占位符,生产环境务必替换为随机密钥]",
  });

  // session 已就绪,可读取或写入 session.data
  return session.data;
});

初始化成功后,响应里会带上一个 Set-Cookie,cookie 名默认是 h3,内容是加密后的会话数据。如果后续请求带着名为 h3 的 cookie、或名为 x-h3-session 的请求头,H3 就会据此还原会话。

💡 cookie 与 header 二选一:x-h3-session 请求头优先于 cookie。这意味着你可以把会话通过 header 传递(例如在服务端之间转发、或某些不允许用 cookie 的运行环境),不必依赖浏览器自动带 cookie。

读取会话数据

数据存在 session.data 上,没有数据时是个空对象:

import { useSession } from "h3";

app.use(async (event) => {
  const session = await useSession(event, {
    password: process.env.SESSION_PASSWORD ?? "[演示占位符]",
  });
  return session.data; // 可能是 {},也可能是之前写入的内容
});

写入:自增访问次数

import { useSession } from "h3";

app.use(async (event) => {
  const session = await useSession(event, {
    password: process.env.SESSION_PASSWORD ?? "[演示占位符]",
  });

  // 先读旧值(没有就当 0),加一,再写回
  const count = (session.data.count ?? 0) + 1;
  await session.update({ count }); // 底层调用 updateSession

  return count === 1
    ? "欢迎首次访问!"
    : `你已访问本页 ${count} 次`;
});

逻辑是:取出会话 → 没有就新建 → 给 count 加一 → 写回。多访问几次,计数器就会累加。

⚠️ 用 curl 这类不保存 cookie 的命令行工具测试时,你会看到计数一直是 1——因为它每次都是新会话。要把响应里的 Set-Cookie 取出来、下次用 --cookie 回传,才能模拟浏览器的行为。

销毁会话

import { useSession } from "h3";

app.use("/clear", async (event) => {
  const session = await useSession(event, {
    password: process.env.SESSION_PASSWORD ?? "[演示占位符]",
  });
  await session.clear(); // 底层调用 clearSession
  return "会话已清除";
});

clear() 会让 H3 发送一个值为空、过期为 0 的 h3 cookie,浏览器据此删掉它。

安全警告:password 的熵才是真正的边界

⚠️ password 用于封印(seal)每一个会话 cookie,它的熵(随机性)才是真正的安全边界。被窃取的会话 cookie 里,盐值和完整性摘要都是明文携带的——也就是说,拿到 cookie 的人可以离线暴力破解你的 password。提高 PBKDF2 迭代次数只是拖慢破解,并不能修复一个低熵的密钥。

永远用密码学安全的随机源生成它,例如:
sh
# 生成 32 字节随机 base64 串,作为会话封印密钥
node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))"

下面示例为了可读用了硬编码值,但真实项目必须从环境变量(如 process.env.SESSION_PASSWORD)加载一个至少 32 字符的随机密钥,且绝不能提交进源码仓库。一个可被猜到的口令(哪怕长度 ≥32)同样不安全。

H3 HTTP QUERY 方法实战
H3 会话选项与过期
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }