Angular 4-为Facebook动态更新元标记(开放图形)

Angular 4-为Facebook动态更新元标记(开放图形),angular,facebook-graph-api,facebook-opengraph,meta-tags,Angular,Facebook Graph Api,Facebook Opengraph,Meta Tags,我们如何动态添加/更新元标记,以便它们被Facebook/Whatsapp共享对话框选中 我将angular 2应用程序升级到angular 4,以便在从API获取组件中的数据后,使用元服务动态添加/更新元标记 到目前为止,在我的组件中,我已经 this.metaService.updateTag({ property: 'og:title', content: pageTitle }); this.metaService.updateTag({ property: 'og:url', 'www

我们如何动态添加/更新元标记,以便它们被Facebook/Whatsapp共享对话框选中

我将angular 2应用程序升级到angular 4,以便在从API获取组件中的数据后,使用元服务动态添加/更新元标记

到目前为止,在我的组件中,我已经

this.metaService.updateTag({ property: 'og:title', content: pageTitle });
this.metaService.updateTag({ property: 'og:url', 'www.domain.com/page' });
this.metaService.updateTag({ property: 'og:image', content: coverUrl, itemprop: 'image' });
this.metaService.updateTag({ property: 'og:image:url', content: coverUrl, itemprop: 'image' });
this.metaService.updateTag({ property: 'og:image:type', content: 'image/png' });
我使用updateTag是因为我已经添加了带有默认值的静态标记。这段代码在我检查meta标记值时成功地更新了它们

我知道Facebook/Whatsapp调试器工具不执行任何javascript是有道理的,所以它可能永远不会在他们的环境中执行

我正在使用
https://developers.facebook.com/tools/debug/
并且它总是选择有意义的默认标记值


我的问题是,如何让Facebook/Whatsapp动态获取更新的标签值?我使用Angular 4并通过API调用加载所有数据,因此在页面加载和脚本执行之前不可能获取任何类型的数据。

如果您使用Angular 4,为什么不使用Angular Universal创建页面服务器端?这样,您就可以在用户加载页面之前以编程方式构建
HEAD
标记浏览者

Open Graph OG标记必须在源代码中! 您需要提供一个静态html页面,其中包含html源代码中的开放图形标记,如og:image og:title和og:description,因为facebook、twitter和co只是在不通过javascript呈现的情况下删除普通html。Angular通过js动态更新dom,因此爬虫程序只获得初始index.html

有几种方法可以为包含开放图形的html提供服务 如何解决您的问题:

  • 具有角度通用性的服务器端渲染
  • 使用代理呈现页面
  • 动态覆盖index.html替换og标记
  • 提供静态html页面(不确定angular是否支持此功能)
我猜你已经在使用类似于添加og标记的东西了

Angular Universal-在Angular 2/3/4/5中使用元标记进行服务器端渲染 我想服务器端渲染是解决问题的最合适的方法。为此,您可以托管节点服务器或使用AWS Lambda。这样做的缺点是,你的应用程序必须是主动托管的,不能再以静态方式提供服务。无论如何,这似乎是最好的方式,因为它也是改善搜索引擎优化。角度通用是要搜索的术语:

基于构建的角度通用预渲染 您还可以在构建过程中预渲染特定路由,并将其作为具有多个预渲染index.html文件的静态应用程序使用。如果只有很少的静态路由,那么这就非常好了。考虑到更多具有动态零件的通用管线,这不是解决方案。转到服务器端渲染。中还包含了一个示例。看

替代解决方案 使用代理预渲染角度,以提供OG标记 如果您希望避免在构建过程中实现服务器端/预渲染(设置angular universal有时对不好的结构化应用程序来说是一件痛苦的事情),您可以尝试使用代理服务预渲染页面。看一看

覆盖index.html 将所有请求重定向到覆盖og:标记的脚本。这在现代环境中也是可能的。您可以使用cloudfront/api网关和lambda函数。但我还没有看到这样的例子

Facebook缓存和开放图调试 请注意,缓存可能仍然缓存了第一次爬网时打开的图形信息。确保您的源代码是最新的,并且所有缓存、反向代理(如nginxx、cloudfront)都已清除

用于调试打开的图形缓存并清除facebook opengraph缓存尝试以下操作(使用fb API:v2.12):

在第6节中, 动态元标记未反映在index.html中

所以,使用.htaccess获取动态元内容的唯一方法

如果要呈现需要帮助的动态内容,请使用.htaccess

重写cond%{HTTP|u USER|u AGENT}facebook外部点击/1.1 | Twitterbot | Pinterest | linkedinbot | WhatsApp | Viber | SkypeUriPreview | Google.*代码段[NC,或]

有关更多信息:


从2018/19开始,如果你的主要目标是SEO(或者更多的“SMO”-社交媒体优化-因为谷歌机器人在评估JavaScript方面做得很好,但大多数社交媒体机器人没有),那么你选择的SSR解决方案可能不应该是角度通用的,而应该是使用无头浏览器的

这将属于Manuel回答中的“代理”类别,但由于我还没有看到他们在这里发布了两个(半)非常好的解决方案:

这一个是由谷歌Chrome团队自己维护的,它只是呈现应用程序并返回应用程序的一个很好的端点

与Rendertron非常相似,但这一版本已经内置了中间件(即,在何处以及如何决定哪些请求被呈现,哪些请求未被呈现),并且还附带了一些更高级但方便的功能,如缓存。因此,它非常接近“零配置需求”的目标,甚至比Rendertron更容易设置

同样由Google Chrome团队维护(Rendertron实际使用)的Puppeter为无头Chrome提供了基于节点的高级API。因此,如果之前的项目对您来说有两个困难,那么您可能能够使用Puppeter实现一个合适的解决方案,但显然,这将比使用Rendertron或Rendora需要更多的工作

与Angular Universal相比,该解决方案具有巨大的优势,即您的应用程序项目可以完全不知道所使用的SSR工具(它甚至可以使用Angular以外的任何其他技术)。这显然不仅为您自己的代码提供了更大的灵活性,而且也为您的包选择提供了更大的灵活性
FB.ui({
  method: 'share_open_graph',
  action_type: 'og.shares',
  action_properties: JSON.stringify({
    object : {
      'og:url': 'url', // your url to share
      'og:title': 'title',
      'og:site_name':'site_name',
      'og:description':'description',
      'og:image': 'image Url',//
      'og:image:width':'250',//size of image in pixel
      'og:image:height':'257'
    }
  })
}, function(response){
  console.log("response is ",response);
});
RewriteCond … googlebot [NC]
RewriteCond … yandex [NC,OR]
RewriteCond … WhatsApp [NC,OR]
    RewriteEngine On
        
        # https://stackoverflow.com/questions/18406156/redirect-all-to-index-php-using-htaccess
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteCond %{HTTP_USER_AGENT} googlebot|bingbot|yandex|baiduspider|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|quora\ link\ preview|showyoubot|outbrain|pinterest\/0\.|pinterestbot|slackbot|vkShare|W3C_Validator|WhatsApp [NC]
        #        RewriteCond %{HTTP_USER_AGENT} facebookexternalhit|googlebot [NC]   MUST BE WRITTEN WITHOUT OR
        #        RewriteCond %{HTTP_USER_AGENT} googlebot [NC]
        #        RewriteCond %{HTTP_USER_AGENT} facebookexternalhit [NC,OR]          'OR' IS FOR SECOND LINE (AND THIRD AND FOURTH ETC. WON'T WORK ON FIRST LINE)
        RewriteRule ^(.*)$ opengraph.php?q=$1 [NC,L,QSA]

        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^(.*)$ redir.php?orig_path=$1 [NC,L,QSA]

</IfModule>
<?php
  $articleId = $_GET['id'];
  $redirectUrl = 'https://yourapp.com/app/tabs/start/article/'.$articleId;

  // get the article metadata
  $response = file_get_contents('https://api.yourapp.com/articles/'.$articleId);
  $response = json_decode($response);

  $title = $response->title;
  $description = $response->excerpt;
  if(property_exists ($response, 'mainImageUrl') ) {
    $imageUrl = $response->mainImageUrl;
  }
  $publishedTime = $response->published;
?>

<html prefix="og: http://ogp.me/ns#">
<head>
  <title><?php echo $title ?></title>
  <meta name="description" content="<?php echo $description ?>">
  <meta property="og:title" content="<?php echo $title ?>">
  <meta property="og:description" content="<?php echo $description ?>">
  <meta property="og:site_name" content="Your App">
  <meta property="og:locale" content="en_US">
  <meta property="og:type" content="article">
  <meta property="og:url" content="https://yourapp.com/article/<?php echo $articleId ?>">
  <?php if(isset($imageUrl)) { echo '<meta property="og:image" content="'.$imageUrl.'">'; } ?>
  <meta property="og:image" content="<?php echo $imageUrl ?>">
  <meta property="article:published_time" content="<?php echo $publishedTime ?>">

  <script>
    window.location.href = '<?php echo $redirectUrl ?>';
  </script>
</head>
<body>
    <a href="<?php echo $redirectUrl ?>">Click here to proceed...</a>
</body>
</html>