Перейти к содержимому

10. Сессии и Cookies

Remix предоставляет удобные утилиты для работы с сессиями и cookies. Все операции происходят на сервере, что делает их безопасными.

app/session.server.ts
import { createCookieSessionStorage } from "@remix-run/node";
export const { getSession, commitSession, destroySession } =
createCookieSessionStorage({
cookie: {
name: "__session",
httpOnly: true, // Недоступен из JS
path: "/",
sameSite: "lax",
secrets: [process.env.SESSION_SECRET],
secure: process.env.NODE_ENV === "production",
},
});
import { getSession, commitSession } from "~/session.server";
import { redirect } from "@remix-run/node";
export async function action({ request }) {
const formData = await request.formData();
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const user = await verifyLogin(email, password);
if (!user) {
return json({ error: "Неверные данные" }, { status: 400 });
}
const session = await getSession(request.headers.get("Cookie"));
session.set("userId", user.id);
return redirect("/dashboard", {
headers: {
"Set-Cookie": await commitSession(session),
},
});
}
export async function loader({ request }) {
const session = await getSession(request.headers.get("Cookie"));
const userId = session.get("userId");
if (!userId) {
throw redirect("/login");
}
const user = await db.user.findUnique({ where: { id: userId } });
return json({ user });
}
export async function action({ request }) {
const session = await getSession(request.headers.get("Cookie"));
return redirect("/login", {
headers: {
"Set-Cookie": await destroySession(session),
},
});
}

Flash — это данные сессии, которые читаются один раз и удаляются:

// В action после создания записи
session.flash("success", "Пользователь создан!");
return redirect("/users", {
headers: { "Set-Cookie": await commitSession(session) },
});
// В loader следующей страницы
export async function loader({ request }) {
const session = await getSession(request.headers.get("Cookie"));
const message = session.get("success"); // читается и удаляется
return json({ message }, {
headers: { "Set-Cookie": await commitSession(session) },
});
}
import { createCookie } from "@remix-run/node";
export const userPrefs = createCookie("user-prefs", {
maxAge: 604_800, // неделя
});
// В loader
export async function loader({ request }) {
const cookieHeader = request.headers.get("Cookie");
const cookie = await userPrefs.parse(cookieHeader) || {};
return json({ theme: cookie.theme ?? "light" });
}
// В action
export async function action({ request }) {
const cookieHeader = request.headers.get("Cookie");
const cookie = await userPrefs.parse(cookieHeader) || {};
const formData = await request.formData();
cookie.theme = formData.get("theme");
return json({ ok: true }, {
headers: { "Set-Cookie": await userPrefs.serialize(cookie) },
});
}