| 4 min read

随着谷歌开始支持对Ajax站点应用的抓去,那么Angular,Vue或者其他单页应用(SPA) 网站的seo将变得容易得多。但是 # hashbang 符号有着一定的限制。或者那些执着于伪静态url的追求的话,一定是想尽办法去掉这个符号。修改完成之后大家可以参考这个站点fadeit.dk

如何转换为静态路由以及开启html5 mode

前面的例子,大家可以明显看到url中失去了,我们看下angular中的代码吧:

angular.module('main', []).config(['$locationProvider', function($locationProvider) {  
  ...
  $locationProvider.html5Mode(true);
  ...
});

如果你使用的是Apache,则你需要添加重写规则的文件.htcaccess。

RewriteEngine On  
 # If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html

如果你使用nginx 则你需要添加下面的配置,

server {
	# some base configuration
	if (!-e $request_filename) {
		rewrite ^/(.*) /index.html?$1 last;
	}
}

添加这些配置的主要原因就是为了在找不到实际的文件路由重新请求到入口文件,从而进行接下来的路由解析。

如果对于使用服务端的框架类Laravel,Yaf或者Node.js中的一些基本的MVC框架的,你还需要在没有找到具体路由的错误处理那里进行指定跳转到Angular的入口页面。我用Yaf为例,在yaf的错误处理文件error.php中,我必须得添加应对404的处理:

public function errorAction($exception)
    {
    	$file_type = 'html';
        if(strpos($url,'.js')>-1) {
            $file_type = 'js';
        }
        switch ($exception->getCode()) {
            case 516:
            case 517:
                $this->getView()->assign('code','404');
                $this->getView()->assign('msg', '未找到相关页面');
                if($file_type === 'js') {
                    $this->display("js");    
                }else{
                    $path = $_SERVER['REQUEST_URI'];
                    $path_arr = explode('/',$path);
                    $map_path = ['module1','module2','module3'];
                    if(array_search($path_arr[1],$map_path) !== false) {
                        // go to SPA 404
                        $baseModuleName = $path_arr[1];
                        return $this->getView()->display("$baseModuleName/$baseModuleName.tpl");
                    }
                    
                    $this->display('404');
                }
                break;
            default :
                $this->getView()->assign('code',$exception->getCode());
                $this->getView()->assign('msg', $exception->getMessage());
                $this->display("500");
                //echo "code:".$exception->getCode().";<br>msg: ".$exception->getMessage();
                break;
        }
        //echo "code:".$exception->getCode().";<br>msg: ".$exception->getMessage();
    }


当然如果你使用Laravel的话,则你需要添加missing的重写

// index route
Route::get('/', function()
{
    return View::make('index'); // redirect to AngularJS
});

// catch-all -- all routes that are not index or api will be redirected
App::missing(function()
{
    return View::make('index'); // should also redirect to AngularJS
}

如果你在访问的时候遇到下面这个问题,

angular-1.5.3.min.js:1 Error: [$location:nobase] $location in HTML5 mode requires a <base> tag to be present!

楼主去文档看到了大致解决方法有两种:

一种是在head中设置base地址:

<base href="/">
<!--OR -->
<base href="/subapp/">

还有一种通过js设置:

$locationProvider.html5Mode({
  enabled: true,
  requireBase: false
});

这些解决你的url就可以变成这样

xxx.com/detail/12
xxx.com/admin/upload.html

它是如何生效的

HTML5 mode实际上是一个HTML5 History的API,它允许用户通过js设置url,而那些勇于充血的配置则可以将未找到对应资源的页面进行重新加载,而不是产生一个404的响应。如果你的浏览器不支持HTML5 这个属性功能的话,angular的同样会跳转到带有#的url中。

同样对于其他的单页应用,比如你使用vue的话,你也可以通过同样原理进行,配置,详情参考Remove the # hash from URL when using Vue.js in Laravel Homestead

如果你想了解更多关于SPA SEO优化的内容,可以看Making AJAX applications crawlable

参考

You Can Speak "Hi" to Me in Those Ways