记一段SPA的SEO历程:Html5 History Api 大显神通!

背景

想当年,我作了一个新媒体网站项目(AIISPO,已下线)。跟普通资讯网站不同的是,老板要求PC端前台的文章阅读模式必定得是瀑布流+模态框瀑布流指的是以瀑布流的形式将文章罗列出来,而模态框则指的是点击瀑布流中表明文章的某个文块时,直接在当前页面弹出模态框来显示文章正文。javascript

瀑布流式的文章列表

瀑布流式的文章列表

利用模态框直接显示文章正文

点击瀑布流的某个文块后,直接在当前页面弹出模态框来显示正文以及文章相关内容,可依稀透过模态框背景看到底层的瀑布流。点击模态框背景可关闭模态框,至关于回到瀑布流。
利用模态框直接显示文章正文html

日常的开始

其时,我正痴迷于MVVM框架avalon,因而,理所固然地用avalon来渲染瀑布流的DOM树。至于文章正文嘛,就用avalon给瀑布流中的各文块绑定个click事件,顺便把文章id给传到click事件的callback里,执行callback时就ajax读一下文章正文,最后放到模态框里显示就是了。
至此,老板要的“用户体验”就达成了,老板夸我厉害还给我涨工资,我内心美美哒 n(≧▽≦)n前端

问题初现

官网上线了几天,老板给我提出了一个很是“实际”的问题,他无法把文章的网址分享出去呀,这是由于:官网原本就没有独立的文章页面,更勿论文章的网址了!。当务之急是建立出可供分享的文章网址。java

Hashbang登场

老板不接受“跳转新页面”打开文章正文的方案,坚持必定要瀑布流+模态框,我只好琢磨别的思路了。首先我试用window.location.href="/article/1",这是必定会使浏览器跳转而没法保持在当前页面的,pass。接下来我查资料就搜到这Hashbang的方案:利用改变锚点#不会致使页面跳转这一特色,并加上!这一独特的标识,造成形如http://aiispo.cn/#!/article/1的网址。ajax

具体的方案是这样的:后端

  1. 大致上跟最初的方案一致。
  2. 不同的地方在于,打开模态框的同时window.location.href="/#!/article/1",这时地址栏的地址便变为http://aiispo.cn/#!/article/1,也能保持不跳转。
  3. 另外,给document.load绑上callback,也就是在页面加载好后取当前的hash(window.location.hash),会获得形如#!/article/1的字符串。正则匹配该字符串把文章ID取出,就能够直接显示文章正文了。
  4. 在关闭模态框时,应把地址栏恢复回来。

如此一来,用户在阅读文章时地址栏里的正是文章的“网址”,而当用户把网址分享给别人,别人复制到浏览器一打开,就能看到那篇文章了。老板又夸我了,我内心又美美哒 n(≧▽≦)n浏览器

问题再现

官网上线月余,百度仅收录了首页,我打开首页的快照一看,可只有avalon的模板标签,我一会儿就醒悟过来了:百度根本就没能爬到任何的文章,由于首页根本没有任何文章的连接!
这时候我才意识到在SEO方面出了大问题了,这对一个新媒体网站来讲但是致命的呀,把问题报告老板后就赶忙开动脑筋想解决方案了。框架

小尝试

把心一横,把本来用avalon渲染的瀑布流,所有改回用PHP来渲染,同时给瀑布流的文块加上<a>标签,例如<a href="/#!/article/1">。因为加上了<a>标签,地址栏就不须要手动去改了。网站

问题未解

又过了几天,各个搜索引擎仍是没有动静,我便又开始查资料:原来,国内的搜索引擎在抓取页面的时候,是不执行js的。换句话说,搜索引擎从http://aiispo.cn/#!/article/1这样的网址进去,只能看到瀑布流而看不到文章正文,由于文章正文是后面用js渲染的,不执行js就无法渲染,而瀑布流是用PHP渲染成html的,搜索引擎能看获得。听说Google是会执行js的,不过做为一个国内的网站,仍是得优先保证国内的搜索引擎。this

Html5 History Api

思量良久,问题仍是出在文章没有独立的页面上,另外Hashbang这种URL也不可靠,没法被后端识别。痛定思痛,此次必定要完全解决问题。

改造以下:

  1. 仿照模态框的UI,我给作了文章的独立页面,URL形如http://aiispo.cn/article/1
  2. Hashbang不成,我就找其它能修改地址栏但不跳转的方案,结果就找到了Html5 History Api

    1. 把瀑布流文块里的<a href="/#!/article/1">改成<a href="/article/1">
    2. 改这href会致使用户点击后跳转,所以须要用js拦截<a>不让其跳转,并改成用window.history.pushState()来设置地址栏,此时用户的地址栏应为http://aiispo.cn/article/1
    $('#article-list a').on('click', function() {
      var url = $(this).attr('href');
      window.history.pushState(null, null, url);
      return false;
    });
    1. 照样用正则匹配出文章ID,并用模态框显示文章正文。

如此一来,便兼顾了三方的需求:

  1. SEO的需求,搜索引擎抓取瀑布流能抓到文章独立页面的URL(形如http://aiispo.cn/article/1),经过此URL进入文章独立页面能抓取到文章正文。
  2. 用户体验的需求,完美地保留了瀑布流+模态框的阅读模式。
  3. 用户分享文章网址的需求,用户在瀑布流打开文章时,地址栏正是文章独立页面的URL。

兼容性修正

上述方案依赖于Html5 History Api,而IE9及如下版本都是不支持Html5 History Api的,须要进行兼容性修正。
在权衡利弊后,最终决定放弃IE9-用户的用户体验

  1. 检测当前浏览器是否支持Html5 History Api
  2. 不支持的话,就不拦截瀑布流文块的<a href="/article/1">,也就是直接让其跳转。

总结

个人这套方案,本质上跟Prerender没有区别,都是让后端模拟前端渲染的方式生成一个独立的页面供搜索引擎抓取,既兼顾用户体验,又不失SEO

相关文章
相关标签/搜索