koaフレームワークで、以下のミドルウェアとボディーパーサーを使用してセッションを使用したサイトを作成しています。
また、ユーザー管理DBはMongoDB(mongoose)を使用しています。
- koa-session
- koa-passport
- koa-router
- koa-static
- async-busboy(ボディーパーサー)
ユーザー登録画面を作成において、使用済みIDチェックなどの処理は画面リロードなしで行うようFetch APIを使用しています。
特にユーザー登録に成功したときに、そのままサーバー側でログインした状態に移行したいなというときに、躓いたので備忘録としての投稿です。
ユーザー登録画面において、登録ボタン(signupButton)をクリックした際に、Fetch APIでPOSTリクエストを投げます。
クライアント
signupButton.onclick = async evt => {
const res = await fetch('/signup', {
method: 'POST',
body: new FormData(signupForm)
});
const resText = await res.text();
if(resText === 'exists') {
// 使用済みID
}
};
サーバー(Node.js)
router.post('/signup', async ctx => {
const { fields } = await asyncBusboy(ctx.req);
const id = fields.id;
const pass = fields.pass;
const confirmPass = fields.confirmPass;
if (fields.id && fields.pass && fields.pass === fields.confirmPass) {
try {
// DB検索
const user = await User.findOne({ id });
if (user) {
// 使用済みID
ctx.body = 'exists';
} else {
// ユーザー登録
const newUser = new User({ id, password });
await newUser.save();
}
} catch (err) {
// エラー
ctx.body = 'error';
}
}
});
ここで、登録ボタンをクリックすると、ユーザー登録に成功したらそのまま自動的にログイン→ログイン後の画面に遷移したいと思い、コードを以下のように修正しました。
クライアント
// ...
// 'success'だったら'/app'に遷移する処理追加
if(resText === 'success') {
location.href = '/app';
}
if(resText === 'exists') {
// 使用済みID
}
// ...
サーバー(Node.js)
// ...
// ユーザー登録
const newUser = new User({ id, password });
await newUser.save();
await ctx.login(newUser); // passportのloginメソッドを実行し、ログイン状態に移行
ctx.body = 'success'; // 'success'を返す
// ...
これでサーバー側でログイン済みの状態となるようですが、クライアント側は一応URLが'/app'になっているものの、Internal Server Error
と表示されてしまいます。
なぜかと調査すると、そう、クッキーが空のままなのです。
どうしたものかとひと悶着したのち、以下のようにFetch APIで一行付け足すだけで解決しました。
クライアント(ブラウザー)
// ...
const res = await fetch('/signup', {
method: 'POST',
body: new FormData(signupForm),
credentials: 'include' // ←これ追加
});
// ...
これで、'/app'に遷移してもInternal Server Error
とならずにログイン後のページのコンテンツが表示されるようになりました。