不使用getInitialProps时如何在_app服务端渲染获取Next.js上下文
问题说明
移除_app.js中的getInitialProps后,需要同时兼容服务端渲染、客户端渲染场景获取用户请求的accept-language字段,且需要在_app组件中访问Next.js上下文,原有代码的核心问题是服务端逻辑中未正确获取请求上下文对象,以下是可落地的实现方案:
实现方案(适配Pages Router自定义_app.js场景)
核心思路是不重新在_app层加getInitialProps(会导致全站禁用自动静态优化,性能损耗高),分双端逻辑适配:
- 服务端渲染阶段:直接通过Next.js内置的请求头API读取,不需要手动透传
req对象 - 客户端渲染/路由跳转阶段:读取服务端水合时注入的初始值,或中间件提前写入的cookie值,保证双端取值一致
完整代码示例
import { headers } from 'next/headers'; import { NextResponse } from 'next/server'; import type { AppProps } from 'next/app'; import type { NextRequest } from 'next/server'; // 判断当前执行环境 const isClientSide = () => typeof window !== 'undefined'; const getAcceptLanguageString = (): string => { if (!isClientSide()) { // 服务端直接读取当前请求的请求头 const requestHeaders = headers(); return requestHeaders.get('accept-language') ?? 'en-US'; } // 客户端从水合数据或提前写入的cookie中取值 return ( window.__NEXT_DATA__?.props?.pageProps?.acceptLanguage ?? document.cookie.match(/accept-language=([^;]+)/)?.[1] ?? 'en-US' ); }; // 全局中间件统一注入accept-language,不需要每个页面单独处理 export function middleware(req: NextRequest) { const acceptLanguage = req.headers.get('accept-language') ?? 'en-US'; const res = NextResponse.next(); // 写入cookie供客户端路由跳转时读取 res.cookies.set('accept-language', acceptLanguage, { httpOnly: false }); return res; } // 匹配所有路由生效 export const config = { matcher: '/:path*', }; const MyApp = ({ Component, pageProps }: AppProps) => { const acceptLanguage = getAcceptLanguageString(); // 业务逻辑直接使用acceptLanguage即可 return <Component {...pageProps} />; }; export default MyApp;
注意事项
- 不要为了拿上下文在
_app.js中重新添加getInitialProps,会导致所有页面强制走SSR,丢失Next.js的静态优化能力 - 服务端不要手动查找
IncomingMessage对象,直接调用Next.js封装的headers()方法即可获取当前请求上下文的头信息,兼容所有SSR/SSG/ISR场景 - 客户端取值做了多层降级,优先读服务端水合注入的页面属性,其次读中间件写入的cookie,最后兜底默认值,避免出现取值为空的问题
内容的提问来源于stack exchange,提问作者zeckdude
相关产品推荐
相关产品推荐

