简体   繁体   English

Next.js 带有 SSR 的应用程序未预渲染 HTML,因此网络抓取工具无法访问内容

[英]Next js app with SSR is not pre-rendering HTML, so web-scrapers cannot access the content

I have a next.js app that uses server side rendering.我有一个使用服务器端渲染的 next.js 应用程序。 When running the application both locally and in production (on vercel edge), the initial page response is returning what looks like a javascript bundle, and not the fully rendered HTML page.在本地和生产环境中(在 Vercel 边缘)运行应用程序时,初始页面响应返回看起来像 javascript 包的内容,而不是完全呈现的 HTML 页面。 This means that all my SEO is made redundant, as the first response does not contain any of the <meta/> tags that I have defined.这意味着我所有的 SEO 都是多余的,因为第一个响应不包含我定义的任何<meta/>标记。 The page renders correctly in the browser, but I assume web scrapers only look at the initial response from the server.该页面在浏览器中正确呈现,但我假设 web 爬虫仅查看来自服务器的初始响应。

Within the.network tab, the first response with the "document" initiator contains the following:在 .network 选项卡中,带有“文档”发起者的第一个响应包含以下内容:

<!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\u0026token=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\u0026token=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\u0026token=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\u0026libraries=places","strategy":"afterInteractive"}]}</script>
</body>

</html>

I was under the impression that next.js would render full HTML pages on the server before sending them to the browser.我的印象是 next.js 在将它们发送到浏览器之前会在服务器上呈现完整的 HTML 页面。 I am not sure if there is a way to configure a "production" build option within the next.config.js file to make this happen, or whether this is a bug within next itself?我不确定是否有办法在next.config.js文件中配置“生产”构建选项来实现这一点,或者这是否是 next 本身的错误?

The following is my _app.js file:以下是我的 _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;

Any help regarding this would be much appreciated!对此有任何帮助将不胜感激!

I figured this issue out.我想通了这个问题。 I had tried everything I thought I could, but when commenting out the <AuthContextProvider/> it seemed to work completely fine!我已经尝试了所有我认为可以做的事情,但是当注释掉<AuthContextProvider/>时,它似乎工作得很好!

Within the auth context file, I was performing conditional rendering, depending on a loading state, which was causing SSR not to take place:在 auth 上下文文件中,我正在执行条件渲染,这取决于loading state,这导致 SSR 没有发生:

Previously:之前:

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const provider = new GoogleAuthProvider();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user ? user : null);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  const login = () => {
    return signInWithRedirect(auth, provider);
  };

  const logout = async () => {
    setUser(null);
    await signOut(auth);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {!loading && children}
    </AuthContext.Provider>
  );
};

Now:现在:

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const provider = new GoogleAuthProvider();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user ? user : null);
    });
    return () => unsubscribe();
  }, []);

  const login = () => {
    return signInWithRedirect(auth, provider);
  };

  const logout = async () => {
    setUser(null);
    await signOut(auth);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

Well, there are many reasons why there is no rendering HTML the most common problem is there is something that is blocking the rendering, I give an example using Redux-Persist blocks totally the rendering so when you right-click on the page and click on page source you will see not HTML rendering, so you need to check what packages are blocking the rendering because not all NPM packages are very friendly with NextJS and make these behaviors.好吧,没有渲染的原因有很多 HTML 最常见的问题是有一些东西阻止了渲染,我举了一个使用 Redux-Persist 完全阻止渲染的例子,所以当你右键单击页面并单击page source你会看到不是 HTML 渲染,所以你需要检查哪些包阻止了渲染,因为并不是所有的 NPM 包都对 NextJS 非常friendly并做出这些行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM