[解決済み] Next.js 別ページにリダイレクトさせる
質問
私は Next.js で、スタートページ( / ) から /hello-nextjs を例にとって説明します。ユーザーがページを読み込んだ後、パスが === かどうかを判断します。 / にリダイレクトします。 /hello-nextjs
で react-router のようなことをしています。
<Switch>
<Route path="/hello-nextjs" exact component={HelloNextjs} />
<Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
解決方法は?
注意事項
まず、クライアントサイドリダイレクト(React内)、サーバーサイドリダイレクト(301 HTTPレスポンス)、サーバーサイドリダイレクト+認証(301 HTTPレスポンスだが認証チェックのロジックもある)のいずれが必要かを判断する必要があります。 .
これが、私が書ける最も完全な答えです。しかし、ほとんどのシナリオでは、このどれもが必要ではありません。Reactアプリで行うようなリダイレクトを行うだけです。
クライアントサイドのリダイレクションを優先してください。
を使うだけです。
useEffect
+
router.push
で、終わりです。
サーバーサイドのリダイレクトは、特にプライベートなページを安全にしたい場合などに魅力的ですが、本当に必要なのかどうかを見極める必要があります。通常、必要ありません。認証トークンやリフレッシュトークンを管理するような、予想外の複雑さを引き起こすからです。その代わり、例えばゲートウェイサーバーやリバースプロキシ、あるいはその種のチェックを処理するためのアップフロントサーバーをアーキテクチャに追加するとよいでしょう。
Next.jsはReactアプリであり、SSRのようなNext.jsの高度な機能を使うにはコストがかかりますが、それはあなたの文脈で正当化されるべきものであることを心に留めておいてください。
Next 9.4 の回答
こんにちは、すべてのシナリオで動作するコンポーネントの例です。
バルカンネクストスターターwithPrivate access
答えは膨大なので、もし私が何らかの形でSOのルールを破ったら申し訳ありませんが、私は180行のコード片を貼り付けたくありません。SSRと静的エクスポートの両方をサポートしたい場合、Nextでリダイレクトを処理する簡単なパターンはありません。
以下のシナリオは、それぞれ特定のパターンが必要です。
- サーバーサイドレンダリング:許可されればページをレンダリングし、許可されなければHTTPリダイレクトを行う。
- 静的レンダリング (サーバーサイド): 何もレンダリングしませんが、ページをビルドに含めます。
- クライアント側レンダリング、静的エクスポート後:クライアント側でユーザーが認証済みかどうかをチェックし、リダイレクトするかどうかを決定します。このチェック中またはリダイレクト中は、何も表示しません(またはローダーを表示します)。
- next/routerを使用したクライアントリダイレクト後のクライアントサイドレンダリング:同じ動作です。
- SSR後のクライアント側レンダリング: 最初のレンダリングで、getInitialPropsによって渡されたpropsを使用して、ユーザーが許可されているかどうかを直接判断しています。ほんの少し速くなり、空白のフラッシュを避けることができます。
この記事の執筆時点(Next 9.4)では、このような場合は
getInitialProps
ではなく
getServerSideProps
を行うことができなくなります。
next export
.
次回の9.5アップデートは
コメントで @Arthur が述べているように、9.5 では、以下のようなセットアップも可能です。 next.config.jsでリダイレクトを行う。 . この機能の限界は私にはまだわかりませんが、例えばページを移動する必要がある場合や、限られた期間だけアクセスを許可する場合など、グローバルなリダイレクションになるようです。 つまり、リクエストコンテキストにアクセスできないので、例えば認証を扱うためのものではありません。繰り返しになりますが、確認が必要です。
次の10件の新着ドキュメント更新
この解決策は、認証に依存するリダイレクトに特化したものです。
から認証されるのは好きではありません。
getServerSideProps
というのも、リフレッシュトークンの処理など、高度なパターンを設定するのはかなり遅すぎると私は考えているからです。しかし、これが正式な解決策なのです。
また、次のようなアプローチもあります。 このチケットで Vercelのダッシュボードの動作に基づき、認証されていないコンテンツのフラッシュを防ぐことができます(執筆時)。
次の10.2ヘッダーとクッキーに基づく書き換えのアップデート
次の10.2で紹介します。 リライト ヘッダーとクッキーに基づくものです。 これは、認証クッキーやヘッダーの存在に基づいて、サーバーサイドでリダイレクトするための素晴らしい方法です。
ただし、留意してほしいのは、これは セキュア リダイレクトを行います。 ユーザーは偽のトークンでリクエストヘッダを変更することができます。トークンの有効性を実際にチェックし、ヘッダーを正しく設定するために、ゲートウェイ、リバースプロキシ、またはアップフロントサーバーが依然として必要です。
編集:URLは変更されないことに注意してください。リライトは、URLを変更することなく、アプリケーションの既存のページを指す=> それによって、quot;仮想URLを持つことができます。
使用例:あるページがあるとします。
src/contact.tsx
が翻訳され、国際化リダイレクトが設定されています。ページ名そのもの ("contact") を翻訳するには、次のように書き換えます。
/de/kontact
から
/de/contact
.
次の12件の更新
現在 ミドルウェア は、サーバーサイドのリダイレクトを完全に制御することができます。
しかし、ほとんどの場合、クライアント側のリダイレクトとチェックで十分であることを再度心に留めておいてください。
古い回答(動作するが、静的レンダリングが乱雑になる)
準公式な例
は
with-cookie-auth
でリダイレクトする例です。
getInitialProps
. 有効なパターンかどうかはまだわかりませんが、コードはこんな感じです。
Profile.getInitialProps = async ctx => {
const { token } = nextCookie(ctx)
const apiUrl = getHost(ctx.req) + '/api/profile'
const redirectOnError = () =>
typeof window !== 'undefined'
? Router.push('/login')
: ctx.res.writeHead(302, { Location: '/login' }).end()
try {
const response = await fetch(apiUrl, {
credentials: 'include',
headers: {
Authorization: JSON.stringify({ token }),
},
})
if (response.ok) {
const js = await response.json()
console.log('js', js)
return js
} else {
// https://github.com/developit/unfetch#caveats
return await redirectOnError()
}
} catch (error) {
// Implementation or Network error
return redirectOnError()
}
}
サーバーサイドとクライアントサイドの両方を処理します。そのため
fetch
の呼び出しは、実際に認証トークンを取得するものであり、これを別の関数にカプセル化したいと思うかもしれません。
代わりにアドバイスしたいこと
1. サーバーサイドレンダリング時のリダイレクト(SSR時のフラッシュは避ける)
最も一般的なケースです。初回ロード時のページフラッシュを避けるために、この時点でリダイレクトさせたいのです。
MyApp.getInitialProps = async appContext => {
const currentUser = await getCurrentUser(); // define this beforehand
const appProps = await App.getInitialProps(appContext);
// check that we are in SSR mode (NOT static and NOT client-side)
if (typeof window === "undefined" && appContext.ctx.res.writeHead) {
if (!currentUser && !isPublicRoute(appContext.router.pathname)) {
appContext.ctx.res.writeHead(302, { Location: "/account/login" });
appContext.ctx.res.end();
}
}
return { ...appProps, currentUser };
};
2. componentDidMountでリダイレクト(静的モードなどSSRが無効な場合に有効)
これは、クライアントサイドレンダリングのフォールバックです。
componentDidMount() {
const { currentUser, router } = this.props;
if (!currentUser && !isPublicRoute(router.pathname)) {
Router.push("/account/login");
}
}
静的ビルド中にリダイレクトできないので、この点を追加して静的モードで初期ページを点滅させることは避けられませんでしたが、通常のアプローチよりはマシなようです。進展があれば編集してみようと思います。
関連
-
[解決済み】ある要素を別の要素に移動させるには?
-
[解決済み] 電話番号のマークアップはどのように行うのですか?
-
[解決済み] ページを再読み込みせずにURLを変更するにはどうすればよいですか?
-
[解決済み] 画面サイズ、現在のウェブページ、ブラウザウィンドウのサイズを取得する
-
[解決済み] HTMLページからのリダイレクト
-
[解決済み] Reactコンポーネントに条件付きで属性を追加するにはどうすればよいですか?
-
[解決済み] React Router v4で履歴にプッシュする方法は?
-
[解決済み] Reactでブラウザのリサイズ時にビューを再描画する
-
[解決済み】オプションのパスパラメータを持つReact Router
-
[解決済み】react router v4 / v5でネストされたルート
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 名前が''の無効なフォームコントロールはフォーカスされない
-
[解決済み】私のCSS3メディアクエリがモバイルデバイスで機能しないのはなぜですか?
-
[解決済み】スタイルシートとして解釈されるリソースがMIMEタイプtext/htmlで転送される(ウェブサーバーとは関係ないようです)。
-
[解決済み] このCSSでInline-blockが正しく動作しないのはなぜですか?
-
[解決済み] will-change' や translateZ() ハックは 'transition: height' のパフォーマンスを向上させるか?
-
[解決済み] IFrameからボーダーを取り除く
-
[解決済み] Bootstrapのカラム内で画像を中央に配置する方法 [重複]について
-
[解決済み] Favicon.icoを表示させることができません。
-
[解決済み] divが重ならないようにするには?
-
[解決済み] HTML CSS インビジブルボタン