【问题标题】:Is it possible to redirect server-side with internationalization in Next.js?是否可以在 Next.js 中通过国际化重定向服务器端?
【发布时间】:2021-06-24 02:11:48
【问题描述】:

所以我有一个小的 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);

我很高兴知道如何解决这个问题:) 谢谢!

【问题讨论】:

    标签: reactjs typescript redirect next.js server-side-rendering


    【解决方案1】:

    _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 解决其他页面。

    由于无法从带有getInitialProps 的页面访问locale 信息,因此您可以改用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;
    

    【讨论】:

    • 谢谢您的回答,但是在我认为它有效的一分钟后,我收到了错误TypeError: Cannot read property 'locale' of undefined 当我检查文档nextjs.org/docs/api-reference/data-fetching/getInitialProps 时,我注意到,该上下文不包含属性路由器...:/
    • 不幸的是,我仍然遇到同样的错误。当我将 {ctx, router}:NextPageContext 作为参数传递给 getinitialProps 时,它会引发错误,即 NextPageContext 不是正确的类型。当我删除类型声明时,它会再次记录上述错误。
    • 你说得对,我目前的解决方案不起作用。 router 对象仅在 AppContext 中可用 - 传递给 _app 的 getInitialProps 的上下文 - 但不适用于传递给其他页面的上下文。
    • @Bexy-Lyn 我已经更新了我的答案以包括使用getServerSideProps 的可能解决方案。
    • 非常感谢 :) 是的,我现在也得出了同样的结论。 GetServerSideprops 做得更好。
    猜你喜欢
    • 2022-08-08
    • 1970-01-01
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-02
    • 2021-07-15
    • 2021-06-22
    相关资源
    最近更新 更多