Next.js SSR应用未预渲染HTML,爬虫无法获取内容求助
我有一个采用Server Side Rendering(SSR)的Next.js应用,在本地和Vercel Edge生产环境运行时,初始页面响应返回的是JavaScript bundle,而非完全渲染好的HTML页面。这导致我设置的所有<meta/>标签都未出现在初始响应中,SEO完全失效。页面在浏览器中能正常渲染,但网页爬虫只会读取服务器的初始响应。
网络标签中,发起者为“document”的首个响应内容如下:
<!DOCTYPE html> <html> <head> <style data-next-hide-fouc="true"> body { display: none } </style><noscript data-next-hide-fouc="true"> <style> body { display: block } </style> </noscript> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width" /> <meta name="next-head-count" content="2" /><noscript data-n-css=""></noscript> <script defer="" nomodule="" src="/_next/static/chunks/polyfills.js?ts=1665897162450"></script> <script src="/_next/static/chunks/webpack.js?ts=1665897162450" defer=""></script> <script src="/_next/static/chunks/main.js?ts=1665897162450" defer=""></script> <script src="/_next/static/chunks/pages/_app.js?ts=1665897162450" defer=""></script> <script src="/_next/static/chunks/pages/index.js?ts=1665897162450" defer=""></script> <script src="/_next/static/development/_buildManifest.js?ts=1665897162450" defer=""></script> <script src="/_next/static/development/_ssgManifest.js?ts=1665897162450" defer=""></script><noscript id="__next_css__DO_NOT_USE__"></noscript> </head> <body> <div id="__next"></div> <script src="/_next/static/chunks/react-refresh.js?ts=1665897162450"></script> <script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"properties":[{"propertyId":"OsDbKrOmE4wRRUMzalxG","propertyAvg":2.888888888888889,"landlordAvg":2.777777777777778,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FOsDbKrOmE4wRRUMzalxG-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-6214c8e0-4aec-11ed-b51b-75adb81e8353.png?alt=media&token=2437767c-0877-470a-be6a-33f34c906a09","address":"312 Brooklands Road, Timperley, Manchester, UK"},{"propertyId":"NPwjd3YMPA8ddyzqBfmO","propertyAvg":3.888888888888889,"landlordAvg":4.111111111111112,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FNPwjd3YMPA8ddyzqBfmO-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-b8072400-4c4a-11ed-9e75-f5ca509826c3.png?alt=media&token=28ef7da1-711a-485a-8282-ffa1940f767d","address":"1 Wharncliffe Road, Broomhall, Sheffield, UK"},{"propertyId":"rxabfAynk5CfTIPwdRN3","propertyAvg":3.5,"landlordAvg":3,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FrxabfAynk5CfTIPwdRN3-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-7a025420-4c24-11ed-bbda-e9dedbc50f17.jpg?alt=media&token=1da2a00b-76d0-4371-a4e0-b0c77e995db2","address":"324 Grays Inn Road, London, UK"}]},{"__N_SSP":true},"page":"/","query":{},"buildId":"development","isFallback":false,"gssp":true,"scriptLoader":[{"src":"https://maps.googleapis.com/maps/api/js?key=AIzaSyAyIxfU1kI6ODZLE80-_XXyK7tdmY3Gk50&libraries=places","strategy":"afterInteractive"}]}} </script> </body> </html>
我原本以为Next.js会在服务器端渲染完整HTML页面后再发送给浏览器,不确定是否可以通过next.config.js配置生产构建选项实现,还是Next.js本身存在bug?
以下是我的_app.js文件代码:
import React from 'react'; import Head from 'next/head'; import { ThemeProvider } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; import theme from '../config/theme'; import { AppBar, Toolbar, Typography, Container, Box } from '@mui/material'; import { MapsHomeWork } from '@mui/icons-material'; import { Auth, RouteProtect, Link } from '../components'; import { AuthContextProvider } from '../context/authContext'; export const App = ({ Component, pageProps }) => { return ( <AuthContextProvider> <Head> <meta property="og:locale" content="en_GB" /> <meta property="og:site_name" content="Student Property Reviews" /> <meta name="viewport" content="initial-scale=1, width=device-width" /> <meta name="robots" content="index, follow" /> <link rel="icon" href="/favicon.ico" /> </Head> <ThemeProvider theme={theme}> <CssBaseline /> <Box> <AppBar position='static'> <Container maxWidth="xl"> <Toolbar disableGutters> <Link href='/'> <MapsHomeWork sx={{ display: { xs: 'flex', md: 'flex' }, mr: 1 }} /> <Typography variant="h6" sx={{ mr: 2, display: { xs: 'none', sm: 'flex', md: 'flex' }, fontFamily: 'monospace', fontWeight: 700, letterSpacing: '.3rem', color: 'inherit', textDecoration: 'none', }} > STUDENT PROPERTY REVIEW </Typography> </Link> <Auth/> </Toolbar> </Container> </AppBar> <Container sx={{ marginBottom: '25px' }}> <RouteProtect> <Component {...pageProps} /> </RouteProtect> </Container> </Box> </ThemeProvider> </AuthContextProvider> ); }; export default App;
排查
RouteProtect组件问题:从初始响应看,#__next容器为空,说明页面核心内容没在服务器端渲染。RouteProtect如果依赖客户端专属API(如localStorage、window),服务器端无法获取这些值,会导致组件不渲染子内容。建议将权限验证逻辑移到页面的getServerSideProps中,在服务器端完成身份校验后再传递页面数据,避免在组件层面阻塞渲染。修正
Head组件的使用:Next.js的Head组件会在服务器端收集meta标签,但要注意不要重复设置viewport(Next.js默认已添加该标签),重复设置可能导致标签被覆盖或丢失。可以移除_app.js中Head里的<meta name="viewport" />,保留其他SEO相关标签。确保生产环境正确构建:本地开发环境(
next dev)的SSR输出可能和生产环境有差异,生产环境必须执行next build && next start来构建和启动服务。在Vercel上,默认会自动执行生产构建,但要确认项目配置中没有禁用SSR(比如没有错误设置output: 'export')。检查页面组件的SSR兼容性:确认页面组件(如
index.js)没有直接在渲染时使用客户端API,所有依赖客户端的逻辑要放在useEffect或useLayoutEffect中,确保服务器端能正常渲染组件内容。升级Next.js到稳定版本:如果使用的是较旧的Next.js版本,可能存在SSR渲染的bug,升级到最新稳定版可以解决已知问题。
内容的提问来源于stack exchange,提问作者J. Whitehead

