是否可以在 Next.js 中使用国际化重定向服务器端?

Is it possible to redirect server-side with internationalization in Next.js?

所以我有一个小型 Next.js 应用程序,它的页面只允许登录用户使用。那里没什么特别的。 为了管理经过身份验证的路由,我编写了一个在服务器上重定向的 HOC(称为 withAuth),以避免页面在客户端闪烁。到目前为止效果很好,但我有一个问题,我的应用程序是国际化的。所以目前用户只会被重定向到默认语言(英语)的登录,但我更愿意选择他们的语言。

不幸的是,useRouter() 只能在客户端使用,所以我的第一种方法没有成功(我早该知道的)。这是我的代码:

auth.tsx

import redirect from "../utils/redirect";
import * as React from "react";
import { sendData } from "../utils/sendRequest";

export const withAuth = <T extends object>(C: React.ComponentClass<T>) => {
  return class AuthComponent extends React.Component<T> {
    static async getInitialProps({...ctx}: NextPageContext) {
      await sendData('GET','/user').then(response => {
        if (!response || !response.success) {
          redirect(ctx, "/login");
          return {
            user: null,
          };
        }else return {
          user: response.user,
        };
      }).catch(err=>{console.error(err)})

    }

    render() {
      return <C {...this.props} />;
    }
  };
};

redirect.ts

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

const redirect = (context: any, target: string) => {
  let lang = "";
  /*if(!(useRouter.locale == "en")){
    lang = "/"+useRouter.locale; This wont work
  }*/
  if (context.res) {
    context.res.writeHead(303, { Location: /*lang+*/target });
    context.res.end();
  } else {
    Router.replace(/*lang+*/target);
  }
};
export default redirect;

profile.tsx

import * as React from "react";
import { withAuth } from "../components/auth";

//...

class ProfileClass extends React.PureComponent<{}> {
  render() {
    return <Profile />;
  }
}

export default withAuth(ProfileClass);

我很高兴有任何解决这个问题的想法:) 谢谢!

_app 页中 getInitialProps 的解决方案。

您可以从 getInitialProps 上下文对象访问 router 实例,该实例又可以访问当前语言环境。请注意,router 对象仅适用于传递给 _app 的 getInitialProps 的上下文 - 但不适用于传递给其他页面的上下文。

// pages/_app.tsx

static async getInitialProps({ router, ctx }: NextPageContext) {
    const lang = router.locale;

    await sendData('GET','/user').then(response => {
        if (!response || !response.success) {
            redirect(ctx, `${lang}/login`);
            return {
                user: null,
            };
        } else {
            return {
                user: response.user,
            };
        }
    }).catch(err => { console.error(err) })
}

其他页面 getServerSideProps 的解决方案。

由于 locale 信息无法从 getInitialProps 的页面访问,您可以改用 getServerSideProps。这样做涉及重构现有逻辑以适应 getServerSideProps 实施。

首先,我们将重新利用 withAuth 并分离获取用户的逻辑。这会将 user 对象添加到 context 并将其传递给 getServerSideProps.

// /components/auth

export function withAuth(gssp) {
    return async (context: GetServerSidePropsContext) => {
        try {
            const response = await sendData("GET", "/user");
            if (response && response.success) {
                // Add user to context to be used in `getServerSideProps`
                context = { ...context, user: response.user };
            }
        } catch (err) {
            console.error(err);
        }

        return await gssp(context); // Pass `context` and continue on to call `getServerSideProps`
    };
}

然后,withAuth 可用于在您的页面中包装 getServerSideProps 函数,如果未设置 user,将在此处进行重定向。

import * as React from "react";
import { withAuth } from "../components/auth";

export const getServerSideProps: GetServerSideProps = withAuth(async (context: : GetServerSidePropsContext) => {
    if (!context.user) {
        return {
            redirect: {
                destination: `/${context.locale}/login`,
                statusCode: 303
            }
        };
    }

    return {
        props: { 
            user: context.user 
        }
    };
});

class ProfileClass extends React.PureComponent<{}> {
    render() {
        return <Profile />;
    }
}

export default ProfileClass;