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));
}

八、总结 #

本章我们学习了:

  1. 创建Cookie:createCookie函数
  2. Cookie操作:解析、序列化、删除
  3. 多Cookie管理:合并Cookie头
  4. 实际应用:主题、语言、同意
  5. 安全实践:签名和加密

核心要点:

  • 正确配置Cookie安全属性
  • 使用secrets签名敏感数据
  • 合理设置过期时间
最后更新:2026-03-28