本文介绍如何使用HTML5 History API在不刷新页面的情况下改变URL,从而解决AJAX应用的搜索引擎抓取难题。通过pushState方法生成静态URL,结合服务器端noscript标签返回完整HTML,实现前端无刷新交互与后端SEO友好的平衡。
HTML5 History API简介与应用背景
浏览Facebook相册时,用户会发现页面局部刷新且地址栏URL发生变化,且并非使用传统的hash方式。这正是利用了HTML5新增的History API,该API作为window的全局变量存在。在HTML4时代,history.back()和history.go()已是常见用法。
此前认为难以实现,直到看到Discourse创始人Robin Ward的解决方案,令人印象深刻。

Discourse论坛程序重度依赖Ajax,但需确保Google能收录内容。其方案是摒弃井号结构,转而采用History API。
History API允许在不刷新页面的前提下,修改浏览器地址栏显示的URL(即改变网页当前状态)。例如,点击按钮播放音乐后,再点击下方链接,观察现象。

此时地址栏URL已变更,但音乐播放并未中断。
History API的具体细节超出本文范围,其核心作用是在浏览器History对象中添加一条新记录。
相关代码如下:
window.history.pushState(state object, title, url);上述命令可使地址栏显示新URL。History对象的pushState方法接收三个参数,新URL为第三个参数,前两个参数可设为null。
window.history.pushState(null, null, newURL);
目前主流浏览器均支持此方法:Chrome(26.0+)、Firefox(20.0+)、IE(10.0+)、Safari(5.1+)及Opera(12.1+)。
以下是Robin Ward提出的具体实施方法。
前端实现:URL变更与Ajax交互
首先,使用History API替代井号结构,将每个井号链接转换为正常路径URL,以便搜索引擎抓取各个网页。
example.com/1 example.com/2 example.com/3
接着,定义一个JavaScript函数处理Ajax部分,根据网址抓取内容(假设使用jQuery)。
function anchorClick(link) {
var linkSplit = link.split('/').pop();
$.get('api/' + linkSplit, function(data) {
$('#content').html(data);
});
}
随后,定义鼠标的click事件。
$('#container').on('click', 'a', function(e) {
window.history.pushState(null, null, $(this).attr('href'));
anchorClick($(this).attr('href'));
e.preventDefault();
});
还需考虑用户点击浏览器“前进/后退”按钮的情况,这会触发History对象的popstate事件。
window.addEventListener('popstate', function(e) {
anchorClick(location.pathname);
});
完成上述三段代码定义后,即可在不刷新页面的情况下,显示正常路径URL及AJAX内容。
服务器端配置与SEO优化策略
最后,需配置服务器端。
由于不使用井号结构,每个URL均为独立请求。因此,要求服务器端对所有此类请求返回如下结构的网页,以避免404错误。
<html>
<body>
<section id='container'></section>
<noscript>
... ...
</noscript>
</body>
</html>
仔细查看上述代码,会发现其中包含noscript标签,这正是关键所在。
将所有需被搜索引擎收录的内容置于noscript标签内。这样,用户仍可执行AJAX操作而无需刷新页面,同时搜索引擎能收录每个网页的主要内容。