由于 AngularJS 返回的是HTML模板,实际的内容需要执行JS以后才会填充进去,导致百度抓取蜘蛛抓不到,因此产生了 AngularJS 的 SEO 问题。经过几天的研究试验,我们的解决方案是这样的:在后台弄一个 PhantomJS 服务,判断是百度蜘蛛的请求后,就把请求转发给 PhantomJS,由它来解释执行JS,并返回输出给百度蜘蛛。

下面详细说一下具体实现:

后端的项目使用PHP的Zend1框架写的,只用于提供数据接口,前端使用AngularJS1。项目部署在Ubuntu上的Apache上面的。

去掉URL中的“#”

由于 AngularJS 的原因,生成的 URL 中带有“#”,AngularJS需要通过“#”后面的部分来进行页面路由,但百度蜘蛛看不到URL中#之后的部分,所以第一步便是去掉 URL中的 “#”。

js/config/reoute.js 中注入 $locationProvider 对象,$locationProvider需要页面指定<base>路径,这样去掉了#之后能能正确加载js,css文件。

.config(['$stateProvider', '$urlRouterProvider','$httpProvider','$locationProvider',
function($stateProvider,$urlRouterProvider,$httpProvider,$locationProvider){
// ...
$locationProvider.html5Mode(true);

然后是index.html,这是主要的模板,js,css路径是相对于<base>的。

<html>
// ...
<head>
<script type="text/javascript" src="/dist/js/vendor.js"></script>
<script type="text/javascript" src="/dist/js/app.js?v=1.0.3"></script> <base href="/">
</head>
<body>

请求404的问题

取消"#"之后,可以让百度蜘蛛直接访问我们的每个页面了,请求来了,判定为百度蜘蛛,则转发给 PhantomJS 来处理,但问题也出现了,用户正常的访问却变成了404!这是因为URL中“#”后面的部分是AngularJS设定的路由规则,跟我后端没有任何关系,所以会转到404,并返回了。

解决办法就是重写.htaccess规则,让404指向index.html,这样就又走前端路由了。进入正常的前端路由,发送 ajax 请求后端数据再进行页面渲染。

.htaccess文件如下,放/public/根目录下:

RewriteEngine On

 RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L] RewriteRule ^ /index.html

要知道原php项目配置中是指向index.php的。改成这个重写规则,就产生一个新问题,php框架的入口文件index.php也在/public/目录下面,当前端发送ajax请求时,默认接收请求的是index.html,而不是index,php,这就导致ajax请求无法到达。

在之前没有去掉“#”的时候,访问http://www.xxx.com/#/path/sss,请求只到达http://www.xxx.com,重定向到index.html,然后AngularJS读取history对象获得URL,进行路由控制,发出ajax请求(http://www.xxx.com/path/sss),进入index.php,返回相应数据。

我们的解决办法就是把前端项目和后端项目分离出来,前端项目用原有的域名:http://www.xxx.com,而后端项目用:http://api.xxx.com,这样,后端php默认指向index.php,前端项目默认指向index.html。需要在apache中设置一下跨域可访问。为了方便部署,直接把前端项目命名为angular并放在public目录下面,实际上这是两个项目。

前端项目

<VirtualHost *:80>
ServerName www.xxx.com
DocumentRoot /path/xxx/public/angular
DirectoryIndex index.html
<Directory /path/xxx/public/angular>
AllowOverride all
require all granted
</Directory>
</VirtualHost>

后端项目

<VirtualHost *:80>
ServerName api.xxx.com
DocumentRoot /path/xxx/public/
DirectoryIndex index.php
Header set Access-Control-Allow-Origin "http://www.xxx.com"
Header set Access-Control-Allow-Credentials true
<Directory /path/xxx/public/>
AllowOverride all
require all granted
</Directory>
</VirtualHost>

到目前为止,“#”去掉了,用户也能正常访问了,下面就是处理抓取了。

搭建后端js环境

首先,angular项目中.htaccess需要添加几行,变成这样:

RewriteEngine On

 RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L] RewriteCond %{HTTP_USER_AGENT} baiduspider|Googlebot|facebookexternalhit|twitterbot|rogerbot|linkedinbot|embedly|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator|Bingbot|360Spider|Yisouspider|Sogouspider [NC]
RewriteRule (.*) http://seo.xxx.com/url/http://www.xxx.com/$1 [P,L] RewriteRule ^ /index.html

表示如果请求来自搜索引擎蜘蛛,则重定向http://seo.xxx.com。我们在这个域名上部署了一个 PhantomJS 服务。

先弄node环境:

var express = require('express')
var app = express()
app.get('/url/http://*', function (req, res) {
var content = '';
var ourl = req.params[0];
if(!(ourl.indexOf('.css')>-1 || ourl.indexOf('.js')>-1 ||ourl.indexOf('.png')>-1)){
var url = "http://"+req.params[0].replace('_','#');
var exec = require('child_process').exec, last = exec('casperjs casperjs_process.js '+url);
last.stdout.on('data', function (data) {
content += data;
});
last.on('exit', function (code) {
res.send(content);
});
}
})
app.listen('3000','127.0.0.1');

再弄 PhantomJS 服务

var casper = require('casper').create(
{
pageSettings: {
loadImages: false,
loadPlugins: true,
userAgent: 'Mozilla/5.0.8 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36 LBBROWSER'
},
logLevel: "debug",//日志等级
verbose: false, // 记录日志到控制台
waitTimeout:5000
}
);
var url = casper.cli.get(0);
casper.start(url, function() {});
casper.waitForSelector('.ajax-end', function() {});
casper.then(function(){
this.echo(this.getPageContent());
});
casper.run();

这个服务会解释执行所有JS然后返回带有内容HTML响应数据给百度蜘蛛。

PS:个人博客链接:Blog:AngularJS 解决 SEO 问题

AngularJS 解决 SEO 问题的更多相关文章

  1. 前端后端分离,怎么解决SEO优化的问题呢?

    对于90%以上的互联网公司来说,前后端分离是必须要做的.目前接手的公司的一个工程,后端是PHP,用的smarty模板,开发效率和之前公司的完全分离相比,确实低不少,一方面需要前端会PHP,另一方面沟通 ...

  2. angularjs 解决ng-repeat数组内重复对象报错的问题

    ng-repeat 循环数组内元素时,如果数组内元素重复,angular会抛出异常: Error: [ngRepeat:dupes] http://errors.angularjs.org/1.4.3 ...

  3. angularJS解决数据显示闪一下的问题?-解决办法

    转自:https://www.cnblogs.com/e0yu/p/7219930.html?utm_source=itdadao&utm_medium=referral#undefined ...

  4. AngularJs解决表达式闪烁的问题(ng-cloak)

    举例: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8 ...

  5. FreeMarker静态化文件解决SEO推广问题

    1.问题背景 SEO一直是站点对外推广的一个重要手段,如何可以让搜索引擎高速搜索到站点对于增强站点的浏量,提升站点对外形象有着重要意义.那么如何可以对SEO进行优化呢?一个很经常使用的手段就是在网页的 ...

  6. AngularJs 解决浏览器在初始化代码未加载完毕时 而出现闪烁的问题

    1. ng-cloak; 因浏览器会先加载dom元素 而针对于{{pression}} 由于angularjs 还没加载完,会在页面出现闪烁 2.ng-bind; 用ng-bind代替{{expres ...

  7. angularJs解决模态框下echarts不显示问题

    例如:摸态框myModal.html,给它命名一个id,id='myModal'; myModal.html页面想画一个echarts图表 这里是angularJs已经封装好的echarts在html ...

  8. angularJS web应用SEO

    javascript给网站带来丰富的用户体验,越来越多的网站开始应用angularjs/emberjs这类MVC来开发web应用,可以说能够使用native方式来看法的手机app基本都可以使用替代的j ...

  9. 对于angularJS的一点思考

    已经找好工作近两周了,入职基本上还算顺利,自己两年来的挑灯夜战也算是有了收获,于是这两周基本上是按部就班的工作,没有学习什么新技术.在上个公司的时候,同事在项目中使用angularJs,之前他也没有接 ...

随机推荐

  1. 再谈RESTAPI最佳实践

    近一年半,我参与了两到三个项目的工作,这些项目涉及到大量供“外部”使用的REST API,稍后我们会看到为什么要将“外部”这个词放在引号之中.在项目工作期间,我不得不对这些API进行反复地设计,再设计 ...

  2. 非常简单的一个函数 竟然一直没有使用 find()

    find: 在非string类型的容器里,可以直接找出所对应的元素. find函数需要几个参数:迭代器,下标值,所要找的元素 vector<int> a; find(a.begin(),a ...

  3. 如何使用SignalTap II觀察reg與wire值? (SOC) (Verilog) (Quartus II) (SignalTap II)

    Abstract撰寫Verilog時,雖然每個module都會先用ModelSim或Quartus II自帶的simulator仿真過,但真的將每個module合併時,一些不可預期的『run-time ...

  4. Getting Started with Amazon EC2 (1 year free AWS VPS web hosting)

    from: http://blog.coolaj86.com/articles/getting-started-with-amazon-ec2-1-year-free-aws-vps-web-host ...

  5. visual studio 2013 触发挂起事件

    在 VS2013 中调试 winddows phone 或者 win rt 程序的时候,需要手动触发 “挂起” 事件. 如果找不到这个按钮: 1.打开菜单栏中的 “自定义” 对话框: 2.选择调试位置 ...

  6. 删除CNNIC根证书

    操作方法: 1.点击IE工具菜单-->选项-->内容-->证书,在受信任的根证书颁发机构中找到CNNIC Root,将证书导出到桌面备用. 双击CNNIC ROOT查看这个证书的属性 ...

  7. jquery 悬浮验证框架 jQuery Validation Engine

    中文api 地址  http://code.ciaoca.com/jquery/validation-engine/   和bootstarp 一起使用不会像easyui  验证那样生硬 修改版 原版 ...

  8. response.setHeader各种用法

    一秒刷新页面一次 response.setHeader("refresh","1"); 二秒跳到其他页面 (登陆跳转) response.setHeader(& ...

  9. [转]Python中函数的值传递和引用传递

    首先还是应该科普下函数参数传递机制,传值和传引用是什么意思? 函数参数传递机制问题在本质上是调用函数(过程)和被调用函数(过程)在调用发生时进行通信的方法问题.基本的参数传递机制有两种:值传递和引用传 ...

  10. 情商 EQ & 儿童情商

    EQ 包括哪些内容 1. 认知自身情绪的能力(正确客观的评价自己)2. 管理自己情绪的能力(控制冲动) 3. 自我激励能力(学会抗挫折) 4. 认识他人情绪的能力(学会移情) 5. 人际关系处理能力 ...