LoginSignup
0
0

RemixでCookieから値を取得することができない

Posted at

はじめに

Remixでアプリケーションを作っているのですが、Cookie周りで苦戦したのでまとめていきます

問題

RemixはステートではなくCookieで値を保持しておくことが多いため、バックエンドサーバーから送られてきたセッションIDをログイン時にCookieに保存して、トップページに遷移するようなコードを書きました

login.tsx

export const action = async ({ request }: ActionFunctionArgs) => {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const response = await fetch(`${process.env.BE_HOST}/api/users/login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ user: { email, password } }),
  });
  if (response.ok) {
    const sessionData = response.headers.get("Set-Cookie");
    if (!sessionData) {
      return json({ error: "ログインに失敗しました" }, { status: 500 });
    }
    const sessionId = sessionData.split("_session_id=")[1].split(";")[0];

    return redirect("/", {
      headers: {
        "Set-Cookie": sessionId
      },
    });
  } else {
    return json(
      { error: "メールアドレスまたはパスワードが不正です" },
      { status: 401 }
    );
  }
};

そしてログイン時にすでにログイン済みかを以下の関数でチェックするようにしました

export async function requireUserSession(request: Request) {
  const sessionId = await getUserFromSession(request);
  console.log(`sessionId: ${sessionId}`);

  if (!sessionId) {
    throw redirect("/login");
  }

  return sessionId;
}

export async function getUserFromSession(request: Request) {
  const cookie = request.headers.get("Cookie");
  const sessionId = cookie?.split("_session_id=")[1];

  if (!sessionId) {
    return null;
  }

  return sessionId;
}

しかしこの方法でやるとローカルではうまく行くのですが、ステージング環境にデプロイした時になぜかCookieに保存がされずに、sessionIdがnullとなってしまいログインページにリダイレクトされてしまいました

解決方法

ドキュメント通りに実装していくことで解決しました

login.tsx
export const action = async ({ request }: ActionFunctionArgs) => {
  const formData = await request.formData();
  const email = formData.get("email");
  const password = formData.get("password");
  const response = await fetch(`${process.env.BE_HOST}/api/users/login`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ user: { email, password } }),
  });
  if (response.ok) {
    const sessionData = response.headers.get("Set-Cookie");
    if (!sessionData) {
      return json({ error: "ログインに失敗しました" }, { status: 500 });
    }

    const cookieHeader = request.headers.get("Cookie");
    const cookie = (await userPrefs.parse(cookieHeader)) || {};
    cookie.epSessionId = sessionData.split("_session_id=")[1].split(";")[0];

    return redirect("/", {
      headers: {
        "Set-Cookie": await userPrefs.serialize(cookie),
      },
    });
  } else {
    return json(
      { error: "メールアドレスまたはパスワードが不正です" },
      { status: 401 }
    );
  }
};
import { createCookie } from "@remix-run/node";
import { redirect } from "@remix-run/react";

export async function requireUserSession(request: Request) {
  const sessionId = await getUserFromSession(request);
  console.log(`sessionId: ${sessionId}`);

  if (!sessionId) {
    throw redirect("/login");
  }

  return sessionId;
}

export const userPrefs = createCookie("user-prefs", {
  maxAge: 604_800,
});

export async function getUserFromSession(request: Request) {
  const cookieHeader = request.headers.get("Cookie");
  const cookie = (await userPrefs.parse(cookieHeader)) || {};
  const sessionId = cookie.epSessionId;

  if (!sessionId) {
    return null;
  }

  return sessionId;
}

おわりに

私は以下のZennも参考にしたのですが、なぜかデプロイするとCookieが保持できていませんでした

結果的には解決できたのでハードルを超えられたので良かったです

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0