所以我使用MEAN.js构建了一个应用程序,我对文章(博客)部分进行了一些更新,以获得更好的搜索引擎优化,可读性,设计等。但是,我似乎无法弄清楚的一个问题,是如何使用Facebook,Google +,Twitter等分享文章,让他们使用og meta标签填充正确的数据。
我想要什么
我想要的是能够从我的MEAN.js应用程序中分享文章(博客文章),并在社交网站(例如Facebook)中发布链接时显示文章内容。
我做了什么
我尝试过专门为博客文章创建一个单独的服务器布局,但这打破了很多其他事情,我意识到工作量可能不值得 - 必须有一个更聪明的方法。
我也尝试在客户端使用Angular更新og元标记数据,但在社交网站获取这些标记之前,这些值不得更新...换句话说,它实际上并没有我想要它。
我已尝试在呈现索引时抓取Angular路由URL,因此我可以在呈现索引之前更新这些og元值,但我无法在{{1}中的任何位置找到这些值数据。
我认为问题是什么
从概念上讲,这是我认为正在发生的事情:
请求命中我的服务器,但由于它是使用Angular路由的单页应用程序,req
值只是根页(' /&# 39。)
加载索引文件,该文件使用标准服务器模板布局。
Angular被加载并进行AJAX调用以获取Article数据,然后将该数据绑定到页面上的变量。
因此,在Angular甚至找出要抓取的文章信息之前,基本上是在渲染布局(使用og元值)。
我认为理想的解决方案
在我的req.url
文件中,应用的本地变量设置如下:
express.js
这些局部变量随后由Swig在// Setting application local variables
app.locals.siteName = config.app.siteName;
app.locals.title = config.app.title;
app.locals.description = config.app.description;
app.locals.keywords = config.app.keywords;
app.locals.imageUrl = config.app.imageUrl;
app.locals.facebookAppId = config.facebook.clientID;
app.locals.jsFiles = config.getJavaScriptAssets();
app.locals.cssFiles = config.getCSSAssets();
文件中呈现,如下所示:
layout.server.view.html
理想情况下,我认为我们希望在呈现页面之前使用文章特定信息更新这些值。问题是,如果在Angular之前渲染布局,甚至会确定要填充的文章数据,我可以这样做吗?同样,Angular路线似乎无法在// Note the {{keywords}}, {{description}}, etc. values.
<!-- Semantic META -->
<meta id="keywords" name="keywords" content="{{keywords}}">
<meta id="desc" name="description" content="{{description}}">
<!-- Facebook META -->
<meta id="fb-app-id" property="fb:app_id" content="{{facebookAppId}}">
<meta id="fb-site-name" property="og:site_name" content="{{siteName}}">
<meta id="fb-title" property="og:title" content="{{title}}">
<meta id="fb-description" property="og:description" content="{{description}}">
<meta id="fb-url" property="og:url" content="{{url}}">
<meta id="fb-image" property="og:image" content="{{imageUrl}}">
<meta id="fb-type" property="og:type" content="website">
<!-- Twitter META -->
<meta id="twitter-title" name="twitter:title" content="{{title}}">
<meta id="twitter-description" name="twitter:description" content="{{description}}">
<meta id="twitter-url" name="twitter:url" content="{{url}}">
<meta id="twitter-image" name="twitter:image" content="{{imageUrl}}">
对象的任何位置使用,因此我完全不知道如何执行此操作。
所以我回到原来的愿望 - 我怎样才能在社交媒体上分享我的文章&#34;漂亮&#34;使用MEAN.js的方式?我是在正确的轨道上吗?目前的文章设置是否可行?我是否需要构建一个完全没有使用Angular的博客模块?
答案 0 :(得分:2)
我终于在没有Nginx或MEANJS框架之外的任何其他东西的情况下为我的应用程序工作了。你的里程可能会有所不同,但我认为无论如何我都会分享结果。它适用于我,但可能不适合你。
基本上我已经设置的是一种获取非散列URL并重定向到散列URL的方法。因此用户可以共享他们的个人资料,例如example.com/#!/profile/myprofile
,它会重定向到...some stuff here...
//Note the variable names, e.g. {{siteName}}
<meta id="fb-app-id" property="fb:app_id" content="{{facebookAppId}}">
<meta id="fb-site-name" property="og:site_name" content="{{siteName}}">
<meta id="fb-title" property="og:title" content="{{socialTitle}}">
<meta id="fb-description" property="og:description" content="{{socialDescription}}">
<meta id="fb-url" property="og:url" content="{{socialUrl}}">
<meta id="fb-image" property="og:image" content="{{socialImageUrl}}">
<meta id="fb-type" property="og:type" content="website">
...other stuff here...
。
然后我为社交机器人创建了一个单独的布局(虽然回想起来我不确定这是完全必要的)并且当网站被抓取时提供单独的布局。我这样做了:
<强>社交layout.server.view.html 强>
user-agents
然后在我的Express文件中,我明确检查// This code happens just after app.locals variables are set.
// Passing the request url to environment locals
app.use(function(req, res, next) {
// Let's check user-agents to see if this is a social bot. If so, let's serve a different layout to populate the og data so it looks pretty when sharing.
if(req.headers['user-agent'] === 'facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)' ||
req.headers['user-agent'] === 'facebookexternalhit/1.0 (+http://www.facebook.com/externalhit_uatext.php)' ||
req.headers['user-agent'] === 'facebookexternalhit/1.1 (+https://www.facebook.com/externalhit_uatext.php)' ||
req.headers['user-agent'] === 'facebookexternalhit/1.0 (+https://www.facebook.com/externalhit_uatext.php)' ||
req.headers['user-agent'] === 'visionutils/0.2' ||
req.headers['user-agent'] === 'Twitterbot/1.0' ||
req.headers['user-agent'] === 'LinkedInBot/1.0 (compatible; Mozilla/5.0; Jakarta Commons-HttpClient/3.1 +http://www.linkedin.com)' ||
req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 6.1; rv:6.0) Gecko/20110814 Firefox/6.0 Google (+https://developers.google.com/+/web/snippet/)' ||
req.headers['user-agent'] === 'Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)') {
var urlAttempt = req.url;
urlAttempt = urlAttempt.substr(1);
Users.findOne({ link: urlAttempt }, function(err, results) {
if(err) {
res.locals.url = req.protocol + '://' + req.headers.host;
next();
} else if (results !== null) {
// Found link. Populate data.
res.status(200).render('social-index', {
// Now we update layout variables with DB info.
socialUrl: req.protocol + '://' + req.headers.host + req.url,
socialTitle: results.orgName,
socialDescription: results.shortDesc,
socialImageUrl: req.protocol + '://' + req.headers.host + '/profile/img/' + results.imgName
});
} else {
res.locals.url = req.protocol + '://' + req.headers.host;
next();
}
});
} else {
res.locals.url = req.protocol + '://' + req.headers.host;
next();
}
});
以确定是否需要新的布局。如果我找到机器人,我会从我的数据库中获取与URL相关的一些关键数据,然后填充变量,如下所示:
<强> express.js 强>
$url = parse_url(getenv("CLEARDB_DATABASE_URL"));
$server = $url["host"];
$username = $url["user"];
$password = $url["pass"];
$db = substr($url["path"], 1);
$connection = new mysqli($server, $username, $password, $db);
同样,您的里程可能会有所不同,但这对我(部分)有用。我还在努力社交分享整个网址(包括哈希)。希望它在某种程度上有所帮助。
答案 1 :(得分:0)
我遇到了同样的问题。首先我安装了Mean-Seo模块。你可以在mean.js官方github repo上找到它。模块本质上是这样做的:Crawlers(Google等)在遇到SPA URL时会在其请求中添加_escaped_fragment_
部分。 Mean-Seo拦截包括_escaped_fragment_
的请求。然后使用Phantom.Js,从动态HTML中提取静态HTML并保存,将此静态版本提供给抓取工具。
对于Facebook&amp; Twitter,我更改了Mean-Seo的mean-seo.js
文件,在它缓存并保存静态文件之前,我相应地替换了元标记。由于Phantom.Js已经呈现了整篇文章页面,因此您无需再进行其他API调用。只需解析HTML。我还使用cheerio.js
方便地解析HTML。
这种解决了我的问题,但并不完美。我仍然在和hashbang&amp; HTML5模式。当我的网址像https://example.com/post/1
时,Twitter和Facebook不会请求_escaped_fragment_
。
更新:过了一会儿,我放弃了这个行为。 Phantomjs似乎不可靠,我不想为这样的工作浪费系统资源,CPU时间,RAM,磁盘空间。不必要的文件创建也很愚蠢。我目前的做法是这样的:
我为Twitter和Facebook添加了一条新的快速路线。在服务器控制器中,为crawler实现了一个新功能。创建了一个简单的服务器模板,没有Angular,Bootstrap和所有闪亮的东西:只有元标记和简单文本。使用Swig
(已包含在Meanjs中),相应地渲染了此视图模板。我还使用Nginx
作为代理。所以我根据用户代理定义了一个新的Nginx rewrite
。像这样:
if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
rewrite ^/posts/(.*)$ /api/posts/crawl/$1 last;
}
当抓取工具请求帖子的网址时,Nginx会触发我的新简单抓取工具路线并生成小页面。