Next.js 15动态页面刷新后元数据(Metadata)错误渲染至<body>而非<head>的问题求助
Next.js 15动态页面刷新后元数据(Metadata)错误渲染至而非的问题求助
各位Next.js开发者们,我最近在用Next.js 15做项目,采用app目录下export const metadata = { ... }这种官方推荐的最新元数据处理方式,结果遇到了一个非常诡异的问题:
- 首页的标题、关键词这些元数据,都能老老实实渲染在
<head>标签里,完全正常; - 从其他页面通过客户端路由(比如点击Link组件)进入动态页面时,元数据也显示没问题;
- 但一旦刷新这个动态页面,或者直接在新标签页打开它的URL,元数据居然跑到
<body>标签里去了!这直接导致SEO完全失效,太头疼了!
下面是我的相关代码,麻烦大家帮忙看看哪里出问题了:
根布局文件(app/layout.jsx)
import ScrollTop from "../components/common/ScrollTop"; import Header from "@/components/header"; import Footer from "@/components/footer"; import WhatsApp from "@/components/common/WhatsApp"; import CallNow from "@/components/common/CallNow"; import "swiper/css"; import "swiper/css/pagination"; import "swiper/css/navigation"; import "swiper/css/scrollbar"; import "swiper/css/effect-cards"; import "aos/dist/aos.css"; import "../styles/index.scss"; import "../styles/font-awesome/css/all.css"; import { fetchCompanyData } from "@/utils/api/companyAndSeoData"; import { baseURL, username, password } from "@/utils/helper/constants"; export const metadata = { title: "Abhijeet", keywords: "JHjn", verification: { google: "", }, }; export const viewport = { themeColor: 'width=device-width, initial-scale=1', } export default async function RootLayout({ children }) { const web = await fetchCompanyData(baseURL, username, password).catch(() => ({})); return ( <html lang="en"> <head /> <body> <Header web={web}/> {children} <WhatsApp /> <CallNow /> <ScrollTop /> <Footer web={web}/> </body> </html> ); }
动态页面的核心组件(app/[alias]/[slug]/PostServer.jsx)
import React from "react"; import { fetchIndividualPost, fetchRelatedPosts } from "@/utils/api/fetchPost"; import { baseURL, username, password, ImageUrl } from "@/utils/helper/constants"; import Banner from "@/components/common/Banner"; import GalleryTwo from "@/components/hotel-single/GalleryTwo"; import RelatedPostSkeleton from "@/components/skeletons/RelatedPostSkeleton"; import Link from "next/link"; export default async function PostServer({ alias, slug }) { let postData = null; let relatedPost = null; let relatedPostError = null; try { postData = await fetchIndividualPost(baseURL, username, password, alias, slug); if (!postData) throw new Error("Post not found"); } catch (err) { return <p className="text-center text-red-500">{err.message}</p>; } // 单独请求相关文章,避免主请求失败影响页面展示 try { relatedPost = await fetchRelatedPosts(baseURL, username, password, slug); } catch (err) { relatedPostError = err.message; } return ( <> <Banner data={postData} /> <GalleryTwo data={postData} slug={slug} /> {Array.isArray(relatedPost) && relatedPost.length > 0 ? ( <section className="layout-pt-md layout-pb-md mt-10"> <div className="container"> <div className="row mb-2"> <div className="col-12"> <div className="sectionTitle -md text-start"> <h2 className="text-24 font-bold">You may also visit</h2> </div> </div> </div> <div className="row y-gap-30 justify-start items-center mt-2"> {relatedPost.map((post) => ( <div className="col-lg-3" key={post.id}> <div className="card border rounded-4 shadow-sm p-3 card-container" style={{ minHeight: "400px" }}> {post.post_images?.length > 0 && ( <Link href={`/${alias}/${post.slug}`}> <img src={`${ImageUrl}/uploads/post/${post.post_images[0].post_img}`} alt={post.post_images[0].img_alt || post.title} className="rounded-4 mb-3 w-100 object-cover" style={{ height: 150 }} /> </Link> )} <div className="d-flex flex-column h-100"> <div> <Link href={`/${alias}/${post.slug}`}> <h5 className="text-18 font-semibold mb-2 hover:text-[#0451a4] transition-colors"> {post.title} </h5> </Link> <p className="text-14 text-dark-3 mb-3 text-justify"> {post.content?.replace(/<[^>]+>/g, "").slice(0, 100)}... </p> </div> <div className="mt-auto text-center"> <Link href={`/${alias}/${post.slug}`} className="btn btn-primary text-14 font-medium"> Read More → </Link> </div> </div> </div> </div> ))} </div> </div> </section> ) : ( relatedPostError ? null : <RelatedPostSkeleton /> )} </> ); }
动态页面的page.jsx(app/[alias]/[slug]/page.jsx)
我这里的page.jsx很简单,就是把PostServer组件包了一下,代码大概是这样:
import PostServer from './PostServer'; export default async function Page({ params }) { const { alias, slug } = params; return <PostServer alias={alias} slug={slug} />; }
我自己排查过的点:
- 根布局里的
<head>标签是空的,首页能正常注入元数据,所以这块应该没问题吧? - 动态页面目前没有单独导出metadata,是不是需要在page.jsx里根据postData动态生成?但客户端导航时是正常的,刷新就不行,这点我实在搞不懂。
有没有大佬遇到过类似的情况?到底是什么原因导致元数据在刷新动态页时跑到<body>里?应该怎么解决这个问题?万分感谢!
内容来源于stack exchange
相关产品推荐
相关产品推荐

