重定向从/到另一个页面

我是新的在 下一个,我想知道如何重定向从开始页面(/)到 /hello-nextjs的例子。一旦用户加载了一个页面,然后确定是否 path = = /重定向到 /hello-nextjs

反应路由器中,我们这样做:

<Switch>
<Route path="/hello-nextjs" exact component={HelloNextjs} />
<Redirect to="/hello-nextjs" /> // or <Route path="/" exact render={() => <Redirect to="/hello-nextjs" />} />
</Switch>
339183 次浏览

更新: Next.js > = 12.1
正如@warfield 在他的 回答 from next.js > = 12.1中指出的,相对 URL 不再允许重定向,使用它们将抛出一个错误。我在这里重新发布他的答案,希望更多人知道:

使用 中间件和 Next.js > = 12.1重定向:

  1. 创建与 pages目录相同级别的 middleware.ts(或. js)文件
  2. 导出 middleware函数
  3. 创建一个 绝对网址并将其传递给 redirect

TypeScript 示例 middleware.ts:


import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'


export function middleware(request: NextRequest) {
const url = request.nextUrl.clone()
if (url.pathname === '/') {
url.pathname = '/hello-nextjs'
return NextResponse.redirect(url)
}
}


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

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中,你可以在 getServerSidePropsgetStaticProps中使用 redirect键进行 服务器端重定向(请参阅下面的客户端重定向) :

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,也不支持在构建时重定向,如果重定向在构建时已知,您可以添加那些在 < a href = “ https://nextjs.org/docs/message/midware-relevant-urls”rel = “ noReferrer”> next.config.js 内

next.js中,你可以使用 Router ex 重定向 在加载页之后:

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重定向或者更好地使用组件的条件呈现时,通常不是一种很好的/优雅的客户端重定向方法。

我已经创建了一个简单的回购与以上所有的例子 给你

有三种方法。

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 来重定向客户端和服务器端。

redirect-to.ts

import Router from "next/router";


export default function redirectTo(
destination: any,
{ res, status }: any = {}
): void {
if (res) {
res.writeHead(status || 302, { Location: destination });
res.end();
} else if (destination[0] === "/" && destination[1] !== "/") {
Router.push(destination);
} else {
window.location = destination;
}
}

_app.tsx

import App, {AppContext} from 'next/app'
import Router from "next/router"
import React from 'react'
import redirectTo from "../utils/redirect-to"




export default class MyApp extends App {
public static async getInitialProps({Component, ctx}: AppContext): Promise<{pageProps: {}}> {
let pageProps = {};


if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}


if (ctx.pathname === "" || ctx.pathname === "/_error") {
redirectTo("/hello-next-js", { res: ctx.res, status: 301 }); <== Redirect-To
return {pageProps};
}


return {pageProps};
}


render() {
const {Component, pageProps} = this.props;
return <Component {...pageProps}/>
}
}

@ Nico 的回答在你使用类的时候解决了这个问题。

如果使用函数,则不能使用 componentDidMount,而可以使用反作用钩 useEffect


import React, {useEffect} from 'react';


export default function App() {
const classes = useStyles();


useEffect(() => {
const {pathname} = Router
if(pathname == '/' ){
Router.push('/templates/mainpage1')
}
}
, []);
return (
null
)
}

在2019年反应 介绍挂钩。这是更快更有效的比类。

注意

首先,您应该评估是否需要客户端重定向(在 React 中)、服务器端重定向(301 HTTP 响应)或服务器端重定向 + 身份验证(301 HTTP 响应但也有一些检查身份验证的逻辑)

这是我能写出的最完整的答案。但是,在大多数情况下,您不需要这些。就像你在任何 React 应用程序中做的那样重定向。只要使用 useEffect + router.push就行了。

服务器端重定向很有吸引力,特别是当您想要“保护”私有页面时,但是您应该评估是否真正需要它们。通常你不会。它们引入了意想不到的复杂性,比如管理认证标记和刷新标记。相反,您可能希望将网关服务器、反向代理或任何前端服务器添加到您的体系结构中,以处理这类检查。

请记住,Next.js 只是 React 应用程序,使用 Next.js 高级特性(如 SSR)的代价在您的上下文中是合理的。

下一个9.5版本更新

正如@Arthur 在评论中所说,9.5还包括了设置 在 next.config.js 中重定向的可能性。 我还不清楚这个特性的局限性,但它们似乎是全局重定向,例如,当您需要移动一个页面或只允许在有限的时间段内访问时。 因此,它们不是用来处理身份验证的,例如,因为它们似乎不能访问请求上下文。再次确认。

接下来10个新的文件更新

此解决方案特定于根据身份验证进行重定向。

身份验证模式现在已有文档记录

我不喜欢从 getServerSideProps进行身份验证,因为在我看来这太晚了,而且很难设置高级模式,比如处理刷新令牌。但这是官方的解决方案。

您可能还希望根据 Vercel 的仪表板(在编写本文时)的工作方式检查记录在案的 在这张票上方法,该方法可以防止未经身份验证的内容的闪烁

下一个10.2头和基于 Cookie 的重写更新

接下来的10.2介绍了基于标题和 cookie 的 重写。 这是根据身份验证 Cookie 或 Header 的存在来重定向服务器端的一种很好的方法。

但是,请记住,这不是 安全重定向。用户可以使用错误的令牌修改他们的请求标头。您仍然需要网关、反向代理或前端服务器来实际检查令牌的有效性并正确设置标头。

编辑: 注意 URL 不会改变。重写将 URL 指向应用程序的现有页面,而不更改 URL = > ,这允许您拥有“虚拟”URL。

示例用例: 假设您有一个已翻译的页面 src/contact.tsx和 i18n 重定向设置。您可以通过将 /de/kontact重写为 /de/contact来翻译页面名称本身(“ contact”)。

下一次更新

现在,中间件为您提供了对服务器端重定向的完全控制。

然而,请再次记住,在大多数情况下,客户端重定向和检查就足够了。


过时的下一个9.4答案(链接是死抱歉)

嗨,这里有一个可以在所有场景中工作的示例组件:

瓦肯人下一个启动器,有私人通道

这里的示例用法

答案是巨大的,所以很抱歉,如果我打破了这样的规则,但我不想粘贴一段180行的代码。如果您希望同时支持 SSR 和静态导出,那么在 Next 中没有简单的模式来处理重定向。

下列各种情况都需要一个特定的模式:

  • 服务器端呈现: 如果允许,我们呈现页面,如果不允许,HTTP 重定向
  • 静态呈现(服务器端) : 我们什么也不呈现,但是我们仍然在构建中包含页面
  • 客户端呈现后,静态导出: 我们检查客户端用户是否认证,是否重定向。在此检查期间或者重定向期间,我们不显示任何内容(或加载程序)。
  • 在客户端使用 next/router 重定向之后的客户端渲染: 相同的行为。
  • SSR 之后的客户端渲染: 我们使用 getInitialProps 传递的道具来判断用户是否被允许,直接在第一次渲染时。只是快了一点,避免了空白闪光。

在编写本文时(下一步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 {
// https://github.com/developit/unfetch#caveats
return await redirectOnError()
}
} catch (error) {
// Implementation or Network error
return redirectOnError()
}
}

它同时处理服务器端和客户端。fetch调用是实际获取 auth 令牌的调用,您可能希望将其封装到一个单独的函数中。

我的建议是

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. 在组件 DidMount 中重定向(在禁用 SSR 时很有用,例如在静态模式下)

这是客户端呈现的备用方案。

  componentDidMount() {
const { currentUser, router } = this.props;
if (!currentUser && !isPublicRoute(router.pathname)) {
Router.push("/account/login");
}
}

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

完整的例子在这里

相关的问题,可惜最后只有客户能回答

关于重定向的新问题

我已经在我的 Next.JS应用程序中实现了这个功能,通过定义一个根页面来重定向服务器端和客户端。下面是根页面的代码:

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


const redirectTo = "/hello-nextjs";


const RootPage = () => {
useEffect(() => Router.push(redirectTo));
return null;
};
RootPage.getInitialProps = (ctx) => {
if (ctx.req) {
ctx.res.writeHead(302, { Location: redirectTo });
ctx.res.end();
}
};


export default RootPage;

下面是2个复制粘贴级别的示例: 一个用于浏览器,一个用于服务器。

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

假设您希望从 root (/)重定向到一个名为 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

如果你的意图是确保你的应用像 SPA 一样运行,并且想拦截一个传入的无效(或有效)路径名,用户把它粘贴到地址栏,那么这里有一个快速/黑客的方法来做到这一点。

假设你的路径是,

enum ERoutes {
HOME = '/',
ABOUT = '/about',
CONTACT = '/contact'
}

添加一个自定义的 _error页面,如果你还没有一个,并添加到它:

import React from 'react';
import { NextPage } from 'next';
import { useDispatch } from 'react-redux';
import { useRouter } from 'next/router';


const Error: NextPage = () => {
const { asPath, push } = useRouter();
const dispatch = useDispatch();


React.useEffect(() => {
const routeValid = Object.values(ERoutes).includes(asPath);


if (routeValid) {
// do some stuff, such as assigning redux state to then render SPA content in your index page
} else {
// you can either continue to render this _error component, or redirect to your index page,
// where you may have your own error component that is displayed based on your app state.
// In my case, I always redirect to '/' (as you can see below, where I push('/'), but before doing so,
// I dispatch relevant redux actions based on the situation
}


// I redirect to root always, but you can redirect only if routeValid === true
push('/');
}, []);


return (
<div>Error because '{asPath}' does not exist</div>
);
};


export default Error;

适用于 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

Js 10 + 为我们提供了一些额外的、优雅的解决方案来进行重定向。

  1. SERVER-SIDE -您应该使用 getServerSideProps

    下面的例子假设我们有一些额外的会话要检查(但可以是 如果会话是空的,我们在服务器端 (context.res) ,这意味着用户没有登录,我们应该 重定向到登录页面(/login) . . 另一种方式是我们可以传递 session 转至 props,然后重定向至 /dashboard:

    import { getSession } from 'next-auth/client';
    
    
    export const getServerSideProps = async (context) => {
    const session = await getSession(context);
    if(context.res && !session) {
    return {
    redirect: {
    permanent: false,
    destination: '/login'
    }
    }
    }
    
    
    return {
    props: { session },
    redirect: {
    permanent: false,
    destination: '/dashboard'
    }
    }
    }
    
    
    
  2. CLIENT-SIDE -您可以使用例如 useRouter钩子:

    import { useRouter } from 'next/router';
    import { useSession } from 'next-auth/client';
    
    
    const router = useRouter();
    const [ session, loading ] = useSession();
    
    
    if (typeof window !== 'undefined' && loading) return null;
    
    
    if (typeof window !== 'undefined' && !session) {
    router.push('/login');
    }
    
    
    router.push('/dashboard');
    

更多信息请点击: https://github.com/vercel/next.js/discussions/14890

在 NextJs v9.5及以上版本中,您可以在 Next.config.js文件中配置重定向和重写。

但是如果使用 trailingSlash: true,请确保源路径以斜杠结束,以便进行适当的匹配。

module.exports = {
trailingSlash: true,
async redirects() {
return [
{
source: '/old/:slug/', // Notice the slash at the end
destination: '/new/:slug',
permanent: false,
},
]
},
}

您还需要考虑可能影响路由的其他插件和配置,例如 下一张图片

文件: https://nextjs.org/docs/api-reference/next.config.js/redirects

下面是避免 URLs is malformed. Please use only absolute URLs错误的中间件解决方案。

此外,使用路径对象可能是处理重定向的更干净的方法。

// pages/_middleware.ts


import { NextRequest, NextResponse } from 'next/server';


export async function middleware(req: NextRequest) {
const { pathname, origin } = req.nextUrl;


const paths: { [key: string]: string } = {
'/admin/appearance': `${origin}/admin/appearance/theme`,
};


const rePath = paths[pathname];
if (rePath) return NextResponse.redirect(rePath);
else return NextResponse.next();
}

useEffect会重定向,但会立即跳回到当前页面

Something useLayoutEffect的作用就像一种魅力:

const router = useRouter();


useLayoutEffect(() => {
router.isFallback && router.replace("/course");
}, [router]);

我已经使用了相同的代码上面的使用效果。

♂如果有人能解释为什么,提前感谢!

可以设置基路径。下一个 Js 允许您这样做。例如,要使用/login 而不是/(默认) ,打开 next.config.js 并添加 basePath 配置:

  const nextConfig = {
basePath: "/login",
};


module.exports = nextConfig;

你也可以在这里查看他们的文件 https://nextjs.org/docs/api-reference/next.config.js/basepath

Next.js > = 12.1

相对 URL 在重定向中不再允许 ,并将抛出:
Error: URLs is malformed. Please use only absolute URLs.

使用 中间件和 Next.js > = 12.1重定向:

  1. 创建与 pages目录相同级别的 middleware.ts(或. js)文件
  2. 导出 middleware函数
  3. 创建一个 绝对网址并将其传递给 redirect

TypeScript 示例 middleware.ts:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'


export function middleware(request: NextRequest) {
const url = request.nextUrl.clone()
if (url.pathname === '/') {
url.pathname = '/hello-nextjs'
return NextResponse.redirect(url)
}
}


重定向 从 Next.js 9.5开始,您现在可以在重定向键下在 next.config.js 中创建一个重定向列表:

// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/about',
destination: '/',
permanent: true,
},
];
},
};

官方文件