Remix Cookie使用 #
一、Cookie概述 #
Cookie 是存储在浏览器中的小型数据,用于在请求之间保持状态。
二、创建Cookie #
2.1 基本创建 #
tsx
import { createCookie } from "@remix-run/node";
export const userPreferences = createCookie("user-preferences", {
maxAge: 60 * 60 * 24 * 365, // 1年
path: "/",
sameSite: "lax",
});
2.2 安全配置 #
tsx
export const sessionCookie = createCookie("session", {
httpOnly: true,
secure: process.env.NODE_ENV === "production",
sameSite: "strict",
secrets: [process.env.COOKIE_SECRET],
maxAge: 60 * 60 * 24 * 7,
path: "/",
});
2.3 Cookie选项 #
| 选项 | 说明 |
|---|---|
name |
Cookie名称 |
maxAge |
过期时间(秒) |
expires |
过期日期 |
path |
有效路径 |
domain |
有效域名 |
secure |
仅HTTPS |
httpOnly |
禁止JS访问 |
sameSite |
同站策略 |
secrets |
签名密钥 |
三、使用Cookie #
3.1 解析Cookie #
tsx
import type { LoaderFunctionArgs } from "@remix-run/node";
import { userPreferences } from "~/cookies";
export async function loader({ request }: LoaderFunctionArgs) {
const cookieHeader = request.headers.get("Cookie");
const preferences = await userPreferences.parse(cookieHeader);
return json({ preferences });
}
3.2 序列化Cookie #
tsx
import type { ActionFunctionArgs } from "@remix-run/node";
import { userPreferences } from "~/cookies";
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const preferences = {
theme: formData.get("theme"),
language: formData.get("language"),
};
return redirect("/settings", {
headers: {
"Set-Cookie": await userPreferences.serialize(preferences),
},
});
}
3.3 删除Cookie #
tsx
export async function action({ request }: ActionFunctionArgs) {
return redirect("/settings", {
headers: {
"Set-Cookie": await userPreferences.serialize("", {
expires: new Date(0),
}),
},
});
}
四、多Cookie管理 #
4.1 定义多个Cookie #
tsx
export const themeCookie = createCookie("theme");
export const langCookie = createCookie("language");
export const consentCookie = createCookie("consent");
4.2 合并Cookie头 #
tsx
import { userPreferences, themeCookie } from "~/cookies";
export async function action({ request }: ActionFunctionArgs) {
const headers = new Headers();
headers.append("Set-Cookie", await userPreferences.serialize(preferences));
headers.append("Set-Cookie", await themeCookie.serialize(theme));
return redirect("/settings", { headers });
}
五、Cookie类型 #
5.1 JSON数据 #
tsx
export const cartCookie = createCookie("cart", {
maxAge: 60 * 60 * 24 * 7,
});
// 存储
const cart = { items: [{ id: 1, qty: 2 }] };
await cartCookie.serialize(cart);
// 读取
const cart = await cartCookie.parse(cookieHeader);
5.2 简单值 #
tsx
export const themeCookie = createCookie("theme");
// 存储
await themeCookie.serialize("dark");
// 读取
const theme = await themeCookie.parse(cookieHeader);
六、实际应用 #
6.1 主题切换 #
tsx
import { createCookie } from "@remix-run/node";
export const themeCookie = createCookie("theme", {
maxAge: 60 * 60 * 24 * 365,
});
export async function loader({ request }: LoaderFunctionArgs) {
const cookieHeader = request.headers.get("Cookie");
const theme = await themeCookie.parse(cookieHeader) || "light";
return json({ theme });
}
export async function action({ request }: ActionFunctionArgs) {
const formData = await request.formData();
const theme = formData.get("theme");
return redirect(request.url, {
headers: {
"Set-Cookie": await themeCookie.serialize(theme),
},
});
}
6.2 语言偏好 #
tsx
export const langCookie = createCookie("language", {
maxAge: 60 * 60 * 24 * 365,
path: "/",
});
export async function getLanguage(request: Request) {
const cookieHeader = request.headers.get("Cookie");
return await langCookie.parse(cookieHeader) || "zh-CN";
}
6.3 Cookie同意 #
tsx
export const consentCookie = createCookie("consent", {
maxAge: 60 * 60 * 24 * 365,
});
export async function loader({ request }: LoaderFunctionArgs) {
const cookieHeader = request.headers.get("Cookie");
const consent = await consentCookie.parse(cookieHeader);
return json({ hasConsent: consent?.analytics === true });
}
七、安全最佳实践 #
7.1 签名Cookie #
tsx
export const secureCookie = createCookie("secure-data", {
secrets: [process.env.COOKIE_SECRET],
});
7.2 加密敏感数据 #
tsx
import { encrypt, decrypt } from "~/crypto";
export async function setSecureData(data: any) {
const encrypted = await encrypt(JSON.stringify(data));
return secureCookie.serialize(encrypted);
}
export async function getSecureData(request: Request) {
const cookieHeader = request.headers.get("Cookie");
const encrypted = await secureCookie.parse(cookieHeader);
if (!encrypted) return null;
return JSON.parse(await decrypt(encrypted));
}
八、总结 #
本章我们学习了:
- 创建Cookie:createCookie函数
- Cookie操作:解析、序列化、删除
- 多Cookie管理:合并Cookie头
- 实际应用:主题、语言、同意
- 安全实践:签名和加密
核心要点:
- 正确配置Cookie安全属性
- 使用secrets签名敏感数据
- 合理设置过期时间
最后更新:2026-03-28