タイトル: ビューでリダイレクト
SEOタイトル: Laravel リダイレクト完全ガイド
この本文には実行可能なタグ等が含まれるため、安全のためHTMLソースとして表示しています。本文データは変更していません。
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;background:#fffbea;border:1px solid #f4c430;margin:1em 0;width:100%"><tr><td style="background:#f4c430;color:#000;font-weight:bold;padding:8px">この記事の要点</td></tr><tr><td style="padding:10px"><ul><li>Laravel のリダイレクトは <strong><code>redirect()</code></strong> ヘルパーで返す: <code>return redirect('/')</code></li><li>名前付きルート: <code>redirect()->route('home')</code> / 直前ページ: <code>redirect()->back()</code></li><li>ログイン後の意図された URL に戻す: <code>redirect()->intended('/dashboard')</code></li><li>フラッシュメッセージ: <code>->with('flash', '保存しました')</code>、エラー: <code>->withErrors($validator)</code>、入力保持: <code>->withInput()</code></li><li>外部 URL は <code>redirect()->away('https://...')</code>、Blade からは <code><meta http-equiv="refresh"></code> や JS の <code>window.location</code></li></ul></td></tr></table>
<h2>基本: コントローラから redirect() を返す</h2>
<p>Laravel のリダイレクトは「ビューを返す」のではなく「コントローラから <code>RedirectResponse</code> を返す」形が基本です。Blade ファイル内で直接リダイレクトはできません(HTML 出力に <code><meta refresh></code> や JS を書く形になります)。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">public function store(Request $request)
{
// ... 保存処理 ...
// 1. パス直指定
return redirect('/home');
// 2. 名前付きルート
return redirect()->route('home');
return redirect()->route('user.show', ['id' => 1]);
// 3. 直前のページに戻る
return redirect()->back();
return back(); // ヘルパー関数
// 4. アクション指定
return redirect()->action([HomeController::class, 'index']);
}</code></pre>
<h2>リダイレクトメソッド一覧</h2>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>メソッド</th><th>用途</th></tr></thead>
<tbody>
<tr><td><code>redirect('/path')</code></td><td>URL 直指定</td></tr>
<tr><td><code>redirect()->route('name', $params)</code></td><td>名前付きルート(推奨)</td></tr>
<tr><td><code>redirect()->back()</code> / <code>back()</code></td><td>直前のページに戻る</td></tr>
<tr><td><code>redirect()->intended('/default')</code></td><td>認証ミドルウェアが保存した URL に戻る</td></tr>
<tr><td><code>redirect()->action([Ctrl::class, 'method'])</code></td><td>コントローラアクション指定</td></tr>
<tr><td><code>redirect()->away('https://external')</code></td><td>外部 URL(バリデーション通る)</td></tr>
<tr><td><code>redirect()->guest($url)</code></td><td>未認証時のリダイレクト先記録用</td></tr>
<tr><td><code>redirect()->refresh()</code></td><td>同じ URL に再リクエスト</td></tr>
</tbody>
</table>
<h2>フラッシュメッセージ・エラー・入力の保持</h2>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// フラッシュメッセージ(次のリクエストでのみ参照可能)
return redirect()->route('home')
->with('success', '保存しました');
// 複数
return redirect('/')->with([
'status' => 'ok',
'message' => '更新完了',
]);
// バリデーションエラー
return redirect()->back()
->withErrors($validator)
->withInput(); // 入力値を flash して old() で復元
// withInput で特定キーのみ
return back()->withInput($request->only(['email']));
// withInput で特定キー除外
return back()->withInput($request->except(['password']));
// withCookie
return redirect('/')->withCookie(cookie('name', 'value', 60));</code></pre>
<p>Blade 側で受け取る:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{{-- フラッシュメッセージ --}}
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
{{-- バリデーションエラー --}}
@error('email')
<span class="text-red-500">{{ $message }}</span>
@enderror
{{-- 直前の入力値を復元 --}}
<input name="email" value="{{ old('email') }}"></code></pre>
<h2>ログイン後の元のページに戻す: intended()</h2>
<p><code>auth</code> ミドルウェアは未認証ユーザを <code>/login</code> に飛ばすときに、「本来行きたかった URL」をセッションに記録します。ログイン処理後に <code>intended()</code> で読み出します。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">public function login(Request $request)
{
if (Auth::attempt($request->only('email', 'password'))) {
$request->session()->regenerate();
// セッションに保存された intended URL があればそこへ
// なければ '/dashboard'
return redirect()->intended('/dashboard');
}
return back()->withErrors(['email' => '認証失敗']);
}</code></pre>
<h2>HTTP ステータスコードの指定</h2>
<p>SEO 観点でリダイレクトの種別は重要です。Laravel デフォルトは <strong>302 (Found)</strong>。永続的な移転は <strong>301 (Moved Permanently)</strong> を明示します。</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">// 301 永続的リダイレクト
return redirect('/new-path', 301);
return redirect()->route('new.home', [], 301);
// 308 (Permanent Redirect, メソッド保持)
return redirect('/api/v2', 308);
// 303 (See Other, POST → GET 変換)
return redirect('/result', 303);
// レスポンスを後から書き換える
return redirect('/')->setStatusCode(301);</code></pre>
<table border="1" cellpadding="6" cellspacing="0" style="border-collapse:collapse;width:100%">
<thead><tr style="background:#e3f2fd"><th>コード</th><th>意味</th><th>用途</th></tr></thead>
<tbody>
<tr><td>301</td><td>Moved Permanently</td><td>恒久的な URL 変更(SEO 反映)</td></tr>
<tr><td>302</td><td>Found</td><td>一時的(Laravel デフォルト)</td></tr>
<tr><td>303</td><td>See Other</td><td>POST 後の GET 遷移(PRG パターン)</td></tr>
<tr><td>307</td><td>Temporary Redirect</td><td>一時的、メソッド保持</td></tr>
<tr><td>308</td><td>Permanent Redirect</td><td>恒久、メソッド保持</td></tr>
</tbody>
</table>
<h2>外部 URL へのリダイレクト</h2>
<p><code>redirect()</code> はオープンリダイレクト対策で外部 URL に飛ばすと例外が出る場合があります。明示的に外部に飛ばすなら <code>away()</code>:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">return redirect()->away('https://example.com/external');
// ❌ オープンリダイレクト脆弱性に注意
return redirect()->away($request->input('next')); // 危険
// ✅ ホワイトリスト検証してから away
$next = $request->input('next');
$allowed = ['example.com', 'partner.example.com'];
if (in_array(parse_url($next, PHP_URL_HOST), $allowed)) {
return redirect()->away($next);
}
abort(400);</code></pre>
<h2>Blade / フロント側からのリダイレクト</h2>
<p>「ビュー内でリダイレクト」は本来コントローラ側でやるべきですが、どうしても HTML 描画後に飛ばしたい場合:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-html">{{-- meta refresh(3秒後にリダイレクト) --}}
<meta http-equiv="refresh" content="3;URL='/destination'">
{{-- JavaScript --}}
<script>
// 履歴に残す
window.location.href = "{{ route('home') }}";
// 履歴に残さない(戻るボタンで戻れない)
window.location.replace("{{ route('home') }}");
// 遅延
setTimeout(() => location.href = '/', 2000);
</script></code></pre>
<h2>Ajax / API リクエスト時の注意</h2>
<p>Ajax / SPA から POST した場合、サーバが 302 を返してもブラウザは「Ajax レスポンス」として受け取るだけで自動遷移しません。フロント側で <code>response.headers.get('Location')</code> を見るか、JSON で URL を返すパターンが推奨です:</p>
<pre style="background:#1e293b;color:#e2e8f0;padding:1em;border-radius:6px;overflow-x:auto;line-height:1.5"><code class="language-php">if ($request->wantsJson()) {
return response()->json([
'redirect' => route('home'),
'message' => '保存しました',
]);
}
return redirect()->route('home')->with('success', '保存しました');</code></pre>
<h2>FAQ</h2>
<p><strong>Q: <code>redirect()->back()</code> がトップに飛ぶ</strong><br />
A: 直前ページがセッション/Referer から取れない場合の挙動です。<code>back(fallback: route('home'))</code> でフォールバックを指定できます。</p>
<p><strong>Q: 301 にすると以前のリダイレクト先がブラウザにキャッシュされて変更できない</strong><br />
A: ブラウザは 301 を強くキャッシュします。検証中は 302 を使い、本番リリース時のみ 301 に切り替えるのが安全。デバッグ時はシークレットウィンドウや DevTools の Disable Cache で。</p>
<p><strong>Q: フラッシュメッセージが <code>session()</code> から取れない</strong><br />
A: web ミドルウェアグループに属しているか確認。<code>routes/api.php</code> はステートレスでセッションが無効なため <code>with()</code> は機能しません。</p>