AngularJS 解決 SEO 問題


由於 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 問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM