【问题标题】:Dynamic meta descriptions for certain pages in React SPAReact SPA 中某些页面的动态元描述
【发布时间】:2021-09-03 04:40:49
【问题描述】:

我使用 React 构建了一个博客,它从 api 动态获取每个博客条目的数据。 页面的内容显然会根据路线而有所不同,例如mysite.com/blog/1, mysite.com/blog/2, ...

我想要实现的是根据基于 url 从 api 获取的数据动态更改元描述。特别是og:titleog:descriptionog:image。这样的事情可能吗?

我阅读了有关 SSR/Next.JS 或 Gatsby 的信息,但如果数据是从 api 调用接收的,我不确定这是否有效。

我知道 SSR 会在服务器上呈现内容,因此它允许 Google 抓取页面但不会排除 api 调用吗? 我也知道 Gatsby 构建静态站点,但对我来说这行不通,因为 api 调用是动态的,不能构建到静态站点中。

我非常感谢一些提示,可以为我指明正确的方向。

【问题讨论】:

    标签: reactjs gatsby server-side-rendering


    【解决方案1】:

    我知道 SSR 会在服务器上呈现内容,因此它 允许谷歌抓取页面,但不会排除 api 调用? 我也知道 Gatsby 建立静态网站,但对我来说 不起作用,因为 api 调用是动态的,无法构建 进入静态网站。

    我认为你误解了盖茨比的工作原理。

    总而言之,Gatsby 从动态数据(API 调用)生成静态页面,因此,当您运行 gatsby developgatsby build 命令时,Gatsby 从源(在本例中从您的 API)获取数据并生成动态页面(mysite.com/blog/1mysite.com/blog/2 等)。

    此数据是静态的,这意味着这些来源的每次更改都会迫使您重新获取数据以显示更改(在生产中意味着新部署)但是,一旦您的页面是静态构建的,您就可以动态构建您的 SEO 数据。

    这是他们曾经在旧网站上使用的旧版 Gatsby 的工作流程,但我觉得它非常不言自明:

    在构建时,您的网站是静态生成的,因此您可以使用自定义 SEO 组件或任何您想要的东西来完全自定义您的 SEO 要求。大多数启动器都带有一个可以使用的SEO 组件:

    function Seo({ description, lang, meta, title }) {
      const { site } = useStaticQuery(
        graphql`
          query {
            site {
              siteMetadata {
                title
                description
                author
              }
            }
          }
        `
      )
    
      const metaDescription = description || site.siteMetadata.description
      const defaultTitle = site.siteMetadata?.title
    
      return (
        <Helmet
          htmlAttributes={{
            lang,
          }}
          title={title}
          titleTemplate={defaultTitle ? `%s | ${defaultTitle}` : null}
          meta={[
            {
              name: `description`,
              content: metaDescription,
            },
            {
              property: `og:title`,
              content: title,
            },
            {
              property: `og:description`,
              content: metaDescription,
            },
            {
              property: `og:type`,
              content: `website`,
            },
            {
              name: `twitter:card`,
              content: `summary`,
            },
            {
              name: `twitter:creator`,
              content: site.siteMetadata?.author || ``,
            },
            {
              name: `twitter:title`,
              content: title,
            },
            {
              name: `twitter:description`,
              content: metaDescription,
            },
          ].concat(meta)}
        />
      )
    }
    

    由于该组件分别采用descriptionlangmetatitle 作为props,您可以将其添加到您的博客模板中以获取将静态构建的动态数据,这意味着,当您的网站被部署时,该数据将已经构建,因此 Google 抓取工具会立即获取它。

    const YourBlogPostTemplate = ({ data }) =>{    
       
       return <article>
       <SEO title={data.allAPIData.frontmatter.title} />
       <h1>I'm the title: {data.allAPIData.frontmatter.title}</h1>
       </article>
    }
    

    注意:我不会完全自定义它以避免扩展答案,但请理解。

    SEO 组件将采用 title 和构建时的其余字段。

    在构建页面之前获取您的 API 调用,因此,在构建页面时,您的数据已经是静态的。

    【讨论】:

    • 感谢您的回答!但是,由于这是一个动态博客,人们不断地添加新内容(因此是新页面),因此不可能每次都部署构建。我需要为每个添加的新页面进行 SEO。类似于 WordPress 页面,用户可以在其中创建新页面,并且 SEO 将自动起作用。
    • 在这种情况下,盖茨比不符合您的要求
    • 这就是我阅读文档时的想法。可能 SSR 是要走的路。
    【解决方案2】:

    有一篇很好的文章here 描述了如何以最简单的方式解决这个问题。

    基本上,我需要在我当前的 React 应用程序之上放置一个简单的 NodeJS 服务器。服务器现在正在为构建目录中的文件提供服务。对于某些路线,我只是将 __PAGE_META__ 占位符替换为 Google、Facebook、Twitter 等所需的元标记。

    这是描述流程的简单图片:

    以及NodeJS部分的简单代码sn-p:

    const path = require("path")
    const express = require("express")
    const app = express()
    const fs = require("fs")
    //
    const pathToIndex = path.join(__dirname, "build/index.html")
    app.get("/", (req, res) => {
      const raw = fs.readFileSync(pathToIndex)
      const pageTitle = "Homepage - Welcome to my page"
      const updated = raw.replace("__PAGE_META__", `<title>${pageTitle}</title>`)
      res.send(updated)
    })
    //
    app.use(express.static(path.join(__dirname, "build")))
    app.get("*", (req, res) =>
      res.sendFile(path.join(__dirname, "build/index.html"))
    )
    const port = process.env.PORT || 5000
    app.listen(port, () => {
      console.log(`Server started on port ${port}`)
    })
    

    对于动态站点,可以调用一个api,页面元数据可以适当地替换为信息。

    【讨论】:

      猜你喜欢
      • 2013-03-30
      • 1970-01-01
      • 1970-01-01
      • 2021-05-29
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 2021-10-31
      • 1970-01-01
      相关资源
      最近更新 更多