H3 示例总览与 Cookie 处理
前面六章把 H3 的概念、路由、核心 API、工具函数都铺开了。这一章换一种学法:不逐个列 API,而是把官方给出的六个可运行示例拆开讲透。每个示例都对应一类真实需求,照着改就能用。
六个示例覆盖什么
| 示例 | 解决的典型问题 | 对应小节 |
|---|---|---|
| Cookies | 在客户端存一小段数据 | 7.1 |
| HTTP QUERY | 用 GET 的语义但携带结构化请求体 | 7.2 |
| Session | 跨请求记住用户状态 | 7.3 / 7.4 |
| Static Assets | 把本地目录当静态资源对外提供 | 7.5 |
| Streaming | 分块、边生成边发送响应 | 7.6 |
| Validation | 用标准 schema 校验入参 | 7.7 |
这一节先讲最基础的 Cookie——几乎每个示例都会顺手用到它。
三个 Cookie 工具
H3 没有直接让你操作 req / res 上的 cookie,而是提供三个工具函数,全部以 event 为第一个参数:
setCookie(event, name, value, opts?):往响应里挂一个Set-Cookie。getCookie(event, name):从请求里读 cookie,没有时返回undefined。deleteCookie(event, name):让浏览器立刻删掉这个 cookie。
它们的本质是把「序列化 / 解析 cookie 头」这件事封装掉。你不必自己拼 name=value; Path=/; Max-Age=... 这种字符串,setCookie 会替你生成规范的 Set-Cookie 头。
设置 Cookie:选项怎么选
import { setCookie } from "h3";
// 在任意中间件或 handler 里调用即可,无需手动构造响应头
app.use(async (event) => {
setCookie(event, "theme", "dark", {
maxAge: 60 * 60 * 24 * 7, // 有效期 7 天,单位秒
path: "/", // 作用在整站
httpOnly: true, // 禁止前端 JS 读取,防 XSS 偷取
sameSite: "lax", // 默认即可,兼顾可用性与 CSRF 防护
secure: true, // 仅通过 HTTPS 传输
});
return "已写入主题偏好";
});
setCookie 的第三个参数能设的字段和浏览器原生 Set-Cookie 一致,常用的有:
maxAge/expires:过期时间,二选一;maxAge是相对秒数,更直观。path/domain:作用范围。secure:只在 HTTPS 下发送。httpOnly:前端脚本读不到。sameSite:strict/lax/none。
⚠️ 两个最容易被用错的安全选项
-httpOnly:凡是存了登录态、会话 id 这类敏感值的 cookie,必须开httpOnly。开着它,哪怕页面被注入了恶意脚本,也读不到这个 cookie,XSS 偷令牌的链条就此断掉。只有「前端 JS 确实需要读」的非敏感值(比如主题色)才考虑关掉。
-sameSite:现代浏览器默认就是lax,它能挡掉大部分跨站 POST 带 cookie 的 CSRF 场景,同时又放行同站导航带来的 GET。除非你要做真正的跨站携带(如第三方嵌入),否则不要随手设成none——none还要求配合secure: true。
读取与删除
读取就是一行,拿不到返回 undefined,所以判断是否存在要用 if (value !== undefined) 而不是假值判断(空字符串也是合法 cookie 值):
import { getCookie } from "h3";
app.use(async (event) => {
const theme = getCookie(event, "theme"); // 没有就返回 undefined
if (theme === undefined) {
return "尚未设置主题";
}
return `当前主题:${theme}`;
});
删除是 setCookie 的语法糖——把值置空、把 maxAge 设 0,浏览器看到过期时间已到就会立刻清除:
import { deleteCookie } from "h3";
app.use(async (event) => {
deleteCookie(event, "theme"); // 等价于 setCookie(event, "theme", "", { maxAge: 0 })
return "主题已清除";
});
💡 删除时
path/domain必须和当初设置时一致,否则浏览器会把它当成「另一个 cookie」而不去删目标。设置时用了path: "/",删除也带上同样的path最稳妥。
用 curl 验证三条命令
Cookie 是「请求 ↔ 响应」之间来回带的东西,用 curl 验证最直观:
## 1) 设置:看响应头里的 Set-Cookie
curl -i -X POST http://localhost:3000/set
## 2) 读取:把上一步拿到的 cookie 回传,模拟浏览器再次访问
curl --cookie "theme=dark" http://localhost:3000/read
## 3) 删除:再看一次 Set-Cookie,应该是过期时间为 0 的空值
curl -i -X POST http://localhost:3000/del
第一条和第三条用 -i 是为了把响应头打印出来,直接看到 Set-Cookie: theme=dark; ... 和删除时的 Max-Age=0。第二条用 --cookie 手动带上 cookie,模拟浏览器自动回传的行为——这正是浏览器帮你做的事,你在代码里无需操心。