AngularJS如何做SEO

这篇文章是补以前占的坑,欠了好久- -。入职新公司第一个项目,采用了AngularJS作为前端框架,于是再回头补货。

其实之前也研究过这个问题,只不过没有及时做记录,今天再次Google之,做个总结。

单页应用(SPA)默认采取锚点方式(#号)切换路由,而搜索引擎是不识别#后面的内容的,也就是说,无论你的路由怎么变,对于搜索引擎来说,它只能看到页面的基础结构,而没有正文内容,因为它不会执行javascript脚本。比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!doctype html>
<html>
<head>
<meta charset=”utf-8”>
<title></title>
<meta name=”viewport” content=”width=device-width”>
<link rel=”stylesheet” href=”bower_components/bootstrap/dist/css/bootstrap.css”/>
<script src=”bower_components/angular/angular.js”></script>
</head>
<body ng-app=”myApp”>
<div ng-view></div>
<script src=”app.js”></script>
</body>
</html>

这是SPA对搜索引擎不友好的原因。

业界主要有两种解决方案:

一、通过useragent区分搜索爬虫和浏览器

比如国内知名AngularJS站点 http://angularjs.cn/ ,根据http头中的useragent首部识别是搜索引擎还是浏览器访问站点。如果是搜索引擎则调用一个专门的中间件生成完整的html文档返回,让爬虫识别;如果是浏览器访问,则返回正常的只有基本结构的页面,后面的解析交给javascript。

不过这种方式,似乎并不保险,据说有些爬虫是匿名,通过useragent判断不出来,还有可能被认为作弊或是“SEO黑帽”。不过经本人浅测试,google和百度都是能够从 http://angularjs.cn/ 正确搜索出结果的。

 

可参考的文章: AngularJS框架的网站进行SEO的基本原理

二、遵循Google的规则

随着SPA站点的流行,搜索引擎也逐渐认识到不能忽略这些站点。于是Google提出了使用#! (hashbang)作为参数分隔符,在搜索引擎分析SPA站点url的时候,会提取#! 将其替换为 ?_escaped_fragment_=,比如:

1
example.com/#!article/456

将被替换为

1
example.com/?_escaped_fragment_=article/456

向服务器发起请求,然后服务器对_escaped_fragment_参数进行解析,输出完整的html文档,搜索引擎会对这个完整的html进行内容收录。我们要做的就是在前端代码中设置路由前缀:

1
2
3
4
5
6
angular.module('myApp').config([
'$locationProvider',
function($locationProvider) {
$locationProvider.hashPrefix('!');//设置前缀,这样路由分割符为#!,即Google的hashbang
}
]);

如果你的站点使用了HTML5的pushStat API,即在Angular中调用:

1
2
3
4
5
6
angular.module('myApp').config([
'$locationProvider',
function($locationProvider) {
$locationProvider.html5Mode(true);//不使用Angular的默认路由方式,使用pushStat API
}
]);

那么就不会出现hashbang这种形式的路由,你需要在你的页面里添加:

1
<meta name=”fragment” content=”!”>

当搜索引擎匹配到这个meta标记时,会在当前的url 追加?_escaped_fragment_= 重新发起一个请求,你的服务器需要对这个新的请求返回完整的html文档。国外有一些类库实践了这种方案,如 prerender.ioangular-seo 等。

这种方案,跟第一种方案的大体思路类似,都是区分对待搜索引擎和浏览器请求,返回不同的页面,只是区分的手段不同而已。据我了解,目前可能只有Google,Bing,Yahoo三个搜索引擎支持_escaped_fragment_参数的转换,国内的百度等不详,而上一种方案,可能会好一些,或许把两种方案结合起来使用会更好。

注:以上内容,均为本人参考前人的研究做出的一些整理,未做实践(主要验证成本比较高),仅供参考。也许等以后有了实践经验,再来更新本文。

总结

目前国外都是采取第二种方案,因为国外Google没有被墙嘛- -。国内就不是太理想了,两者结合来用会更好吧。另外,网传还有一种方案,是利用noscript标签作为ajax响应的正文内容容器,但似乎不太被推荐(Google建议不要将重要内容放在noscript标签内,或者可以理解为违反了语义化原则),所以本文就不详述了。

可参考的文章:

AngularJS SEO: Get your site indexed and to the top of the search results.

AngularJS SEO with Prerender.io(译文:AngularJS 使用 Prerender.io 处理 SEO 的问题

What you need to know about Angular SEO

如何让搜索引擎抓取AJAX内容?

单页应用SEO浅谈

冷知识:单页应用的搜索引擎优化