警告
首先,您应该评估您是否需要客户端重定向(在 React 内)、服务器端重定向(301 HTTP 响应)或服务器端重定向 + 身份验证(301 HTTP 响应但也有一些逻辑来检查身份验证)。
这是我能写的最完整的答案。但是,在大多数情况下,您不需要任何这些。就像在任何 React 应用程序中一样重定向。首先首选客户端重定向。只需使用useEffect
+ router.push
,就是这样。
服务器端重定向很诱人,特别是当您想要“保护”私人页面时,但您应该评估您是否真的需要它们。通常,你不会。它们会带来意想不到的复杂性,例如管理身份验证令牌和刷新令牌。相反,您可能希望向您的体系结构添加网关服务器、反向代理或任何前端服务器,例如处理这些类型的检查。
请记住,Next.js 只是 React 应用程序,使用 Next.js 等高级功能(如 SSR)需要付出一定的代价,这在您的上下文中是合理的。
下一个 9.4 答案
嗨,这是一个适用于所有场景的示例组件:
Vulcan next starter with Private access
示例用法在这里
答案是巨大的,很抱歉,如果我以某种方式违反了 SO 规则,但我不想粘贴 180 行代码。如果你想同时支持 SSR 和静态导出,在 Next 中没有简单的模式来处理重定向。
以下场景均需要特定模式:
- 服务器端渲染:如果允许,我们渲染页面,否则 HTTP 重定向
- 静态渲染(服务器端):我们什么都不渲染,但我们仍然将页面包含在构建中
- 客户端渲染,在静态导出后:我们检查客户端是否用户是 auth,并重定向与否。在此检查或重定向期间,我们不显示任何内容(或加载程序)。
- 使用 next/router 进行客户端重定向后的客户端呈现:相同的行为。
- SSR 后的客户端渲染:我们使用 getInitialProps 传递的 props 来判断用户是否被允许,直接在第一次渲染时使用。它只是快了一点,你避免了一个空白的flash。
在撰写本文时(Next 9.4),您必须使用getInitialProps
,而不是getServerSideProps
,否则您将失去执行 的能力next export
。
下一个 9.5 更新
正如@Arthur 在评论中所述,9.5 还包括在 next.config.js 中设置重定向的可能性。我还不清楚这个功能的局限性,但它们似乎是全局重定向,例如,当您需要移动页面或仅允许在有限时间内访问时。因此,例如,它们并不打算处理身份验证,因为它们似乎无权访问请求上下文。再次,有待确认。
接下来的 10 个新文档更新
此解决方案特定于取决于身份验证的重定向。
现在记录身份验证模式
我不喜欢从 进行身份验证getServerSideProps
,因为在我看来为时已晚,并且很难设置高级模式,例如处理刷新令牌。但这是官方的解决方案。
您可能还想根据 Vercel 的仪表板的工作方式(在撰写本文时)检查此故障单中记录的方法,以防止未经身份验证的内容闪烁
下一个 10.2 基于标头和 cookie 的重写更新
下一个 10.2 介绍基于标头和 cookie 的重写。这是基于身份验证 cookie 或标头的存在重定向服务器端的好方法。
但是,请记住,这不是安全的重定向。用户可以使用虚假令牌更改他们的请求标头。您仍然需要网关、反向代理或前置服务器来实际检查令牌有效性并正确设置标头。
编辑:注意 URL 不会改变。重写将 URL 指向应用程序的现有页面,无需更改 URL => 它允许您拥有“虚拟”URL。
用例示例:假设您有一个src/contact.tsx
已翻译的页面和 i18n 重定向设置。您可以通过重写/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时避免flash)
这是最常见的情况。此时您想重定向以避免初始页面在首次加载时闪烁。
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");
}
}
我无法避免在静态模式下闪烁初始页面添加这一点,因为您无法在静态构建期间重定向,但它似乎比通常的方法更好。我会在取得进展时尝试编辑。
完整的例子在这里
相关问题,遗憾的是最终只有客户回答
我打开的关于重定向的新问题