是否可以在 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;
所以我有一个小型 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;