ログイン後のページ復帰設計:beforeunloadとHistory APIの注意点と実装例

ユーザーがログインした後に、それまで見ていたページへ自動的に戻す仕組みは、ECサイトや会員制サービスで頻繁に見られる要件です。この機能を実装するにあたり、まず思い浮かぶのがページ離脱時のイベントである beforeunload と、ブラウザの履歴を操作する History API です。しかし、どちらも一長一短があり、そのままでは目的を達成できません。本記事では、それぞれの挙動を確認しながら、最終的に採用した現実的な実装パターンを紹介します。

ページ離脱時のイベント beforeunload

beforeunload イベントは、ユーザーがページを離れようとしたとき(タブを閉じる、別のURLへ遷移するなど)に発火します。元のページを離れる瞬間に情報を記録しておけば、ログイン後に戻せるのではないか、と考えたのがきっかけでした。

window.addEventListener('beforeunload', (event) => {
  console.log('離脱が検出されました');
});

このコードを実行すると、ほぼすべてのページ遷移やブラウザ終了時にコンソール出力が行われます。一見便利に見えますが、あらゆる移動で処理が走るため、実際のアプリケーションに組み込むには負荷が大きすぎます。

また、beforeunload 内では window.open() や window.alert() などのポップアップ系メソッドがブロックされる制限があります。ブラウザはユーザー体験を損なわないように、離脱時の新しいウィンドウ生成を禁止しているためです。

よく知られている使い方として、編集中のデータが失われることを防ぐダイアログを表示する例があります。ただし、現在の主要ブラウザではカスタムメッセージは無視され、統一された文言だけが表示されます。下記のコードはその実装パターンです。

window.addEventListener('beforeunload', (e) => {
  // ダイアログを出すために必須
  e.preventDefault();
  e.returnValue = '';
  // 古いブラウザ向けの戻り値
  return '';
});

このとき、以下のようなブラウザ標準の確認ダイアログが表示されます。

ブラウザの離脱確認ダイアログ例

カスタムメッセージが反映されない点や、イベントが高頻度で発生する点を考慮すると、ログイン前のページ保存という目的には適しません。

History API による履歴の操作

続いて、ブラウザが自動的に管理している履歴を利用する方法を検討しました。window.history オブジェクトを使えば、明示的に前のページへ戻ることができます。

// 1つ前のページへ戻る
window.history.back();

// 1つ先のページへ進む
window.history.forward();

// 任意のステップ数移動(-2 なら2つ戻る)
window.history.go(-2);

開発者ツールで window.history を確認すると、次のように履歴の長さなどが参照できます。

window.history のプロパティ例

この仕組みなら、ログインが完了したタイミングで history.back() を呼べば、直前のページに戻れるように思えます。しかし、大きな問題があります。履歴はブラウザ全体で共有され、サイト外の遷移も含めて記録されるためです。たとえば、ユーザーがブックマークから直接ログインページを開いた場合、直前の履歴が全く関係ないサイトになっている可能性があります。その状態で back() を実行すると、ユーザーは意図しない外部サイトへ飛ばされてしまいます。

したがって、履歴に頼るだけでは安全なログイン後リダイレクトを実現できません。

手動でのURL保存と復元による実装

結局、beforeunload の副作用も History API の不確実性も避けつつ、必要なタイミングだけ自前で記録するアプローチに落ち着きました。具体的には、以下の2つの場面で現在のURLを保存します。

  • 画面上のログインボタンをクリックしたとき
  • APIの認証切れなどでプログラム的にログインページへ飛ばすとき

保存先には sessionStorage を用いることで、タブを閉じればデータが消え、余計な残留を防ぎます。ログイン処理が成功した後に、保存しておいたURLへ location.href で移動させる設計です。

/**
 * 現在のページURLを一時保存する
 */
function storeCurrentPage() {
  sessionStorage.setItem('previousPage', window.location.href);
}

/**
 * ログイン成功後に、保存したURLがあればそこへ遷移し、
 * なければデフォルトのページへ移動する
 */
function navigateToPreviousPage(defaultPath = '/') {
  const savedUrl = sessionStorage.getItem('previousPage');
  if (savedUrl) {
    window.location.href = savedUrl;
    // 再利用を防ぐために削除
    sessionStorage.removeItem('previousPage');
  } else {
    window.location.href = defaultPath;
  }
}

// 使用例:ログインボタンのクリックハンドラ
document.getElementById('loginButton').addEventListener('click', () => {
  storeCurrentPage();
  // ログインページへ遷移する処理(例)
  window.location.href = '/login';
});

// ログイン処理完了後のコールバック
function onLoginSuccess() {
  // 認証情報の保存など
  // ...
  navigateToPreviousPage('/home');
}

このパターンであれば、余計なイベント監視が不要で、外部からの直接アクセスにも対応できます。大規模なフロントエンドフレームワーク(Angular、React、Vueなど)を利用している場合も、サービスクラスや状態管理の中に同様のロジックを組み込むことで、全ページ共通の振る舞いとして実装できます。

ポイントは、ログイン画面へ移動する直前にのみ保存処理を走らせることと、デフォルトの戻り先を必ず用意しておくことです。これにより、ユーザーがどのような経路でログイン画面に到達したとしても、意図通りの画面遷移が保証されます。

タグ: javascript beforeunload History API sessionstorage Redirect

10月8日 18:32 投稿