注意事项
首先,你需要评估是否需要客户端重定向(在React中),服务器端重定向(301 HTTP响应)或者服务器端重定向+身份验证(301 HTTP响应,但也要有一些逻辑来检查身份验证)。
这是我能写的最完整的答案。但是,在大多数情况下,你不需要任何东西。只需像在任何React应用程序中一样进行重定向。首选客户端重定向。只需使用useEffect
+router.push
即可。
服务器端重定向很诱人,特别是当你想要“保护”私有页面时,但你应该评估是否真的需要它们。通常情况下,你不需要它们。它们引起了意外的复杂性,比如管理授权令牌和刷新令牌。相反,你可能希望添加一个网关服务器、反向代理或其他预处理服务器到你的架构中,以处理这些类型的检查。
请记住,Next.js只是React应用程序,使用Next.js高级功能,如SSR,会带来一些成本,这些成本应该在你的上下文中得到证明。
Next 9.5更新
正如@Arthur在评论中所述,9.5还包括在next.config.js
中设置重定向的可能性。
这个功能的限制对我来说还不清楚,但它们似乎是全局重定向,例如当你需要移动一个页面或只允许在有限期间内访问时。
因此,它们并不适用于处理身份验证,因为它们似乎无法访问请求上下文。再次确认。
Next 10新文档更新
这个解决方案特定于根据身份验证进行重定向。
身份验证模式现在已经记录在文档中
我不喜欢从getServerSideProps
进行身份验证,因为在我看来,它太晚了,而且在处理刷新令牌等高级模式时可能会很难设置。但这是官方解决方案。
你还可以检查基于Vercel仪表板的此票证所记录的方法,该方法防止未经身份验证的内容闪烁。
Next 10.2基于头和cookie的重写更新
Next 10.2引入了基于头和cookie的重写。
这是一种基于身份验证cookie或标题的服务器端重定向的好方法。
然而,请记住这不是一个安全的重定向。用户可以使用虚假令牌更改其请求标头。您仍需要一个网关、反向代理或前置服务器来实际检查令牌有效性并正确设置标头。
编辑:请注意,URL 不会更改。重写将 URL 指向应用程序中现有页面,而不更改 URL => 它允许您拥有“虚拟” URL。
示例用例:想象一下,您有一个页面 src/contact.tsx,并进行了翻译和 i18n 重定向设置。您可以通过将 /de/kontact 重写为 /de/contact 来翻译页面名称本身(“contact”)。
下一个 12 更新
现在
middlewares 让您完全控制服务器端重定向。
然而,请再次记住,大多数时候客户端重定向和检查就足够了。
过时的 Next 9.4 答案(链接已失效,抱歉)
嗨,这里有一个在所有场景下都有效的示例组件:
Vulcan next starter withPrivate access
示例用法在此处
答案很长,如果我某些方面违反了 SO 规则,请见谅,但我不想粘贴一段 180 行的代码。在 Next 中,没有简单的模式来处理重定向,如果您想同时支持 SSR 和静态导出。
以下各种情况需要特定的模式:
- 服务器端渲染:如果允许,则渲染页面;否则进行 HTTP 重定向。
- 静态渲染(服务器端):我们不渲染任何内容,但仍将页面包含在构建中。
- 客户端渲染,在静态导出后:我们检查客户端是否经过身份验证,并根据需要进行重定向。在此检查期间或者如果我们正在重定向时,我们不显示任何内容(或加载器)。
- 使用 next/router 进行客户端重定向后的客户端渲染:同样的行为。
- SSR 后的客户端渲染:我们使用通过 getInitialProps 传递的 props 来告诉是否允许用户在第一次渲染时直接使用。这只是稍微快一点,您可以避免空白闪烁。
在撰写本文时(Next 9.4),您必须使用 getInitialProps
,而不是 getServerSideProps
,否则将失去使用 next export
的能力。
更过时的旧答案(有效,但静态渲染会很混乱)
半官方示例
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 {
return await redirectOnError()
}
} catch (error) {
return redirectOnError()
}
}
它处理服务器端和客户端。
fetch
调用实际上是获取身份验证令牌的,您可能希望将其封装到单独的函数中。
我建议的替代方案
1. 服务器端重定向(避免 SSR 期间的闪烁)
这是最常见的情况。您希望在此时进行重定向,以避免初始页面在第一次加载时闪烁。
MyApp.getInitialProps = async appContext => {
const currentUser = await getCurrentUser();
const appProps = await App.getInitialProps(appContext);
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 };
};
在componentDidMount中进行重定向 (在静态模式下禁用SSR时非常有用)
这是客户端渲染的后备方案。
componentDidMount() {
const { currentUser, router } = this.props;
if (!currentUser && !isPublicRoute(router.pathname)) {
Router.push("/account/login");
}
}
由于在静态构建期间无法重定向,因此我无法避免在静态模式下闪现初始页面,但这似乎比通常的方法更好。我会在进展中尝试进行编辑。
完整示例在此处
相关问题,可悲的是只有客户端回答
我开了一个新问题,涉及重定向