NextJS 13(App目录)多语言NotFound页面实现问题求助
Next.js 13 App目录本地化NotFound页面问题解决方案
一、"Unsupported Server Component type: Null"错误的可能原因
notFound()调用后存在无效返回:在Server Component中调用notFound()后,若后续代码返回null(比如未处理的条件分支),会触发该错误。Server Component要求必须返回有效的React节点,不能返回null。- 路由布局导出异常:
[locale]路由组的layout.tsx可能未正确导出组件,或组件内部逻辑返回null。 not-found.tsx组件问题:根目录或路由组内的not-found.tsx默认导出为null,或组件渲染逻辑返回null。- 版本兼容bug:早期Next.js 13版本(如13.0.x)存在本地化NotFound页面的处理bug,建议升级至13.4+稳定版。
二、含路由组嵌套布局的多语言NotFound页面实战示例
路由结构
app/ ├── [locale]/ │ ├── layout.tsx │ ├── page.tsx │ ├── not-found.tsx │ └── [...not-found]/ │ └── page.tsx ├── not-found.tsx ├── layout.tsx └── middleware.ts
核心代码实现
- middleware.ts:处理语言路由与偏好头
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' export function middleware(request: NextRequest) { // 从Cookie获取用户语言偏好,默认'en' const preferredLocale = request.cookies.get('NEXT_LOCALE')?.value || 'en' // 重定向到对应locale路由 if (!request.nextUrl.pathname.startsWith(`/${preferredLocale}`)) { return NextResponse.redirect( new URL(`/${preferredLocale}${request.nextUrl.pathname}`, request.url) ) } // 设置响应头用于布局获取locale const response = NextResponse.next() response.headers.set('X-Language-Preference', preferredLocale) return response } // 匹配所有非静态资源、API的路由 export const config = { matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'], }
- [locale]/layout.tsx:嵌套布局,动态设置html lang属性
import type { Metadata } from 'next' export async function generateMetadata({ params: { locale }, }: { params: { locale: string } }): Promise<Metadata> { return { title: locale === 'zh' ? '本地化应用' : 'Localized App', } } export default function LocaleLayout({ children, params: { locale }, }: { children: React.ReactNode params: { locale: string } }) { // 直接用路由参数locale设置lang,确保客户端导航时自动更新 return ( <html lang={locale}> <body>{children}</body> </html> ) }
- [locale]/[...not-found]/page.tsx:捕获路由组内未匹配路由,触发notFound
import { notFound } from 'next/navigation' export default function NotFoundCatchAll() { // 调用notFound后,Next.js会自动渲染同路由组的not-found.tsx notFound() }
- [locale]/not-found.tsx:路由组内的本地化NotFound页面
import Link from 'next/link' import { useParams } from 'next/navigation' export default function LocaleNotFound() { const { locale } = useParams() as { locale: 'en' | 'zh' } const i18n = { en: { title: '404 - Page Not Found', desc: 'The page you requested could not be found.', backBtn: 'Return to Homepage', }, zh: { title: '404 - 页面未找到', desc: '你请求的页面不存在。', backBtn: '返回首页', }, }[locale] return ( <div className="flex flex-col items-center justify-center h-screen p-4"> <h1 className="text-4xl font-bold mb-4">{i18n.title}</h1> <p className="text-lg mb-6">{i18n.desc}</p> <Link href={`/${locale}`} className="px-6 py-2 bg-blue-600 text-white rounded"> {i18n.backBtn} </Link> </div> ) }
- 根not-found.tsx:兜底的全局NotFound页面
import Link from 'next/link' export default function RootNotFound() { return ( <div className="flex flex-col items-center justify-center h-screen p-4"> <h1 className="text-4xl font-bold mb-4">404 - Page Not Found</h1> <p className="text-lg mb-6">The page you requested could not be found.</p> <Link href="/en" className="px-6 py-2 bg-blue-600 text-white rounded"> Return to Homepage </Link> </div> ) }
客户端导航lang属性更新说明
上述[locale]/layout.tsx直接使用路由参数locale设置html lang属性,而非仅依赖服务端请求头,因此客户端导航时会自动更新lang属性值,解决你遇到的该问题。
内容的提问来源于stack exchange,提问作者Fabio Nettis
相关产品推荐
相关产品推荐

