我如何在单页应用程序的子页面上动态生成标题的 LInkedin / FB 上共享标题和元数据?

问题描述

我已经在 Angular 中设置了一个单页应用程序,目前根据路由动态设置页面标题和 OG/元参数。即例如每次在应用程序中使用此更改路线时。 titleService 还会更新页面页面标题和元标记

import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

import { Component,OnInit } from '@angular/core';
import { Router,NavigationEnd,ActivatedRoute } from '@angular/router';
import { Title } from '@angular/platform-browser';

@Component({...})
export class AppComponent implements OnInit {
  constructor(
    private router: Router,private activatedRoute: ActivatedRoute,private titleService: Title
  ) {}
  ngOnInit() {
    this.router.events
      .filter((event) => event instanceof NavigationEnd)
      .map(() => this.activatedRoute)
      .map((route) => {
        while (route.firstChild) route = route.firstChild;
        return route;
      })
      .filter((route) => route.outlet === 'primary')
      .mergeMap((route) => route.data)
      .subscribe((event) => this.titleService.setTitle(event['title']));
  }
}

现在的问题是,当我在 Linkedin 上共享我的应用程序的子页面之一时,它不会根据我在应用程序中动态生成的参数更新 URL 的标题和 OG 项,而是显示标题在我的应用路由前设置。

我如何分享到 Linkedin / Facebook,以便它根据我页面上动态更新的标题显示标题和描述?

解决方法

使用单页 Web 应用程序更新元数据只会在客户端更新它。 LinkedIn、Facebook 和其他社交共享网站不会加载和解释 JavaScript。他们只是获取从服务器返回的 HTML 文件并使用其中包含的任何元数据。因此,在 JavaScript 中实现的自定义路由和相关数据将永远不会被读取,而是始终显示默认值。

虽然有许多可能的解决方案,但所有解决方案都需要大量的工作,并且根据您的项目范围各有利弊。您可以考虑在服务器上预先构建 HTML 以进行初始页面加载或在发送之前在服务器上调整 HTML 文件的元数据。

简单的预渲染方法:

预渲染元数据的一种方法是让脚本在您构建使用调整后的元数据创建单个 html 页面的代码后运行。 (免责声明:我主要使用 React 而不是很多 Angular,因此示例可能略有偏差,但跨框架的总体思路应该是相同的)

以这个文件为例 -
https://github.com/cid-harvard/growth-lab-app-front-end/blob/master/prerender-metadata.js

这里我读入了构建的 index.html 文件,通过使用正则表达式来修改每个路由的元数据来查找和替换一组关键字符(放置在 HTML 模板文件中),然后保存为一个单独的 HTML 文件,用于提供适当的元数据(但在页面完全加载时将以相同的方式运行 SPA)。

为了便于搜索和替换,HTML 模板包含如下“默认”元数据:

<title>$OG_TITLE</title>
<meta name="description" content="$OG_DESCRIPTION" />

我在构建脚本之后使用简单的 node prerender-metadata.js

运行上述脚本

一个简单的服务器端渲染方法:

使用相同的风格构建带有可搜索字符串的 HTML 模板,您还可以在服务器上执行类似的搜索和替换以获得更多动态内容。不是在构建步骤之后立即运行脚本,而是在每次请求特定 url 时在服务器上运行它。这是在服务器上使用 express 和 Node 的示例:

app.get('/terms-of-use',(req,res) => {
  const filePath = path.resolve(__dirname,'../../client','build','index.html');
  // read in the index.html file
  fs.readFile(filePath,'utf8',function(err,data) {
    if (err) {
      return console.error(err);
    }
    // replace the special strings with server generated strings
    data = data.replace(/\$OG_TITLE/g,'Terms of Use');
    const result  = data.replace(/\$OG_DESCRIPTION/g,"Terms of Use.");
    res.send(result);
  });
});