Next.js 从/重定向到另一个页面

IT技术 html reactjs routing react-router next.js
2021-04-11 02:14:13

我是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>
6个回答

更新:Next.js >= 12
现在您可以使用中间件进行重定向_middleware.js在 pages 文件夹(或 pages 内的任何子文件夹)中创建一个文件

import { NextResponse, NextRequest } from 'next/server'
export async function middleware(req, ev) {
    const { pathname } = req.nextUrl
    if (pathname == '/') {
        return NextResponse.redirect('/hello-nextjs')
    }
    return NextResponse.next()
}

更新:Next.js >= 10

从 Next.js 10 开始,您可以使用内部进行服务器端重定向(请参阅下面的客户端重定向)redirectgetServerSidePropsgetStaticProps

export async function getServerSideProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()
  // or use context.resolvedUrl for conditional redirect
  // if(context.resolvedUrl == "/")
  if (!data) {
    return {
      redirect: {
        destination: '/hello-nextjs',
        permanent: false,
      },
    }
  }

  return {
    props: {}, // will be passed to the page component as props
  }
}

注意:使用getServerSideProps将强制应用程序到 SSR,也不支持在构建时重定向,如果在构建时已知重定向,您可以在next.config.js 中添加这些

next.js您可以使用ex加载页面后重定向Router

import Router from 'next/router'

componentDidMount(){
    const {pathname} = Router
    if(pathname == '/' ){
       Router.push('/hello-nextjs')
    }
}

或使用钩子:

import React, { useEffect } from "react";
import Router from 'next/router'

...
useEffect(() => {
   const {pathname} = Router
   if(pathname == '/' ){
       Router.push('/hello-nextjs')
   }
 });

如果你想在重定向之前防止闪烁,你可以使用一个简单的技巧:

import React, { useEffect,useState } from "react";
import Router from 'next/router'
const myPage = ()=>{
    const [loaded,setLoaded] = useState(false)
    useEffect(() => {
        const {pathname} = Router
        // conditional redirect
        if(pathname == '/' ){
            // with router.push the page may be added to history
            // the browser on history back will  go back to this page and then forward again to the redirected page
            // you can prevent this behaviour using location.replace
            Router.push('/hello-nextjs')
           //location.replace("/hello-nextjs")
        }else{
            setLoaded(true)
        }
      },[]);

    if(!loaded){
        return <div></div> //show nothing or a loader
    }
    return ( 
        <p>
            You will see this page only if pathname !== "/" , <br/>
        </p> 
    )
}
export default myPage

我会说,当您可以使用next.config.js重定向甚至更好地使用组件的条件渲染时,通常不是进行客户端重定向的好/优雅方法

我创建一个简单的回购与上面的例子都在这里

SSR呢?初始页面用这种方法闪烁
2021-06-04 02:14:13
不使用类
2021-06-13 02:14:13
同意这个问题并不完全清楚“一旦页面加载意味着什么”。使用 React-Router 时,SSR 是开箱即用的,因此客户端和服务器之间没有区别。
2021-06-14 02:14:13
@EricBurel OP 明确询问“一旦用户加载页面”顺便检查这个github.com/zeit/next.js/issues/649
2021-06-15 02:14:13
我如何处理 React 钩子?
2021-06-19 02:14:13

警告

首先,您应该评估您是否需要客户端重定向(在 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");
    }
  }

我无法避免在静态模式下闪烁初始页面添加这一点,因为您无法在静态构建期间重定向,但它似乎比通常的方法更好。我会在取得进展时尝试编辑。

完整的例子在这里

相关问题,遗憾的是最终只有客户回答

我打开的关于重定向的新问题

在 v9.5.0 中,可以将重定向添加到 next.config.js- link这样您就可以更新您的答案(如果它是相关信息)
2021-05-24 02:14:13
嗨@EricBurel。你能帮我解决这个问题吗?stackoverflow.com/questions/69403655/…谢谢
2021-06-02 02:14:13
像你一样的气味也是从 /login 页面重定向的,所以你会得到一个无限循环。
2021-06-04 02:14:13
谢谢!关于可以使用重定向的上下文,文档并不完全清楚:它是否在“导出”模式下工作,您是否可以request在 SSR 期间访问该对象?据我所知,这些是全局重定向,就像您移动了一条路线,或者您有一个页面可用于有限数量的类型,适用于每个用户。需要更多测试/更多反馈来更新我的答案。
2021-06-20 02:14:13

有三种方法。

1.重定向事件或函数:

import Router from 'next/router';

<button type="button" onClick={() => Router.push('/myroute')} />

2.使用钩子重定向:

import Router , {useRouter}  from 'next/router';

const router = useRouter()

<button type="button" onClick={() => router.push('/myroute')} />

3.使用链接重定向:

基于 Nextjs 文档,<a>链接内标签是必需的,例如在新标签页中打开!

import Link from 'next/link';

<Link href="/myroute">
   <a>myroute</a>
</Link>

服务器端路由还有一些其他选项,即asPath. 在所有描述的方法中,您可以添加 asPath 来重定向客户端和服务器端。

问题是关于根据当前路由路径名自动重定向。您的答案有效但不适用于此上下文:它们都需要用户单击。
2021-05-23 02:14:13
我没明白你的意思!?
2021-05-26 02:14:13
这是一种势在必行的方法。可以根据用户操作进行重定向,但不能根据问题中所述的页面加载条件进行重定向。
2021-05-30 02:14:13
你好!你可以看看我的解决方案
2021-06-06 02:14:13
@EricBurel,是的,这不是我想要的,这个答案没有解决我的问题
2021-06-08 02:14:13

适用于 NextJS 9.5.0+

  1. 创建next.config.js文件
  2. 添加源和目标 url(如果是外部域,您可以设置为永久重定向)
module.exports = {
  async redirects() {
    return [
      {
        source: '/team',
        destination: '/about',
        permanent: false,
      },
      {
        source: "/blog",
        destination:
          "https://blog.dundermifflin.com",
        permanent: true,
      },
    ];
  },
};


https://github.com/vercel/next.js/tree/canary/examples/redirects

我可以知道永久重定向和非永久重定向有什么区别吗?我无法理解非永久性重定向。
2021-06-18 02:14:13

这里有 2 个复制粘贴级别的示例:一个用于浏览器,一个用于服务器。

https://dev.to/justincy/client-side-and-server-side-redirection-in-next-js-3ile

假设您想从根 (/) 重定向到名为 home 的页面:(/home)

在您的主索引文件中,粘贴以下内容:

客户端

import { useRouter } from 'next/router'

function RedirectPage() {
  const router = useRouter()
  // Make sure we're in the browser
  if (typeof window !== 'undefined') {
    router.push('/home')
  }
}

export default RedirectPage

服务器端

import { useRouter } from 'next/router'

function RedirectPage({ ctx }) {
  const router = useRouter()
  // Make sure we're in the browser
  if (typeof window !== 'undefined') {
    router.push('/home');
    return; 
  }
}

RedirectPage.getInitialProps = ctx => {
  // We check for ctx.res to make sure we're on the server.
  if (ctx.res) {
    ctx.res.writeHead(302, { Location: '/home' });
    ctx.res.end();
  }
  return { };
}

export default RedirectPage
谢谢。Next.js中关于Client-Side和Server-Side Redirects的解释,加上 本文给出的HOC抽象,真的很有value!
2021-06-07 02:14:13