今天做项目发现一个奇怪的现象,我的路由配置里有如下配置:

1
2
3
4
5
6
7
8
<?php
Route::group(array('prefix'=>'admin','before'=>'adminauth'),function(){
    // 管理员登录
    Route::get('/',function(){
        return Redirect::to('admin/login');
    });
    Route::get('login','UserController@adminLogin');
};

目的是无论用户输入admin,还是admin/login都能跳转到登录界面。然而现实情况是输入admin之后,浏览器会无限重定向,firebug记录如下:

GET /public/admin/ 301 Moved Permanently GET admin 301 Moved Permanently
GET admin 301 Moved Permanently
GET /public/admin/ 301 Moved Permanently
GET admin 301 Moved Permanently
GET /public/admin/ 301 Moved Permanently
GET admin 301 Moved Permanently
….

经过一番搜索后试验,终于得出结论,问题有两点:

  1. public目录下正好有个admin目录,存放后台相关js和css

  2. laravel自带的.htaccess的这样一条规则:

    RewriteEngine On
    # Redirect Trailing Slashes…
    RewriteRule ^(.*)/$ /public/$1 [L,R=301] #注意这条
    # Handle Front Controller…
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]

解释一下原理:

访问public/admin目录时,apache会自动转成public/admin/的形式,而这种形式正好符合重写的规则,又被重写回public/admin的形式。因为public/admin目录确实存在,所以请求根本不会到达index.php。

所以故事就是这样,因为301那条规则的存在,无限重定向产生了。

解决方案:

  1. 不要把public目录下已有的目录名做为路由地址
  2. 301规则前加一条RewriteCond %{REQUEST_FILENAME} !-d,但是这样会使该目录被直接访问。建议生产环境中关掉apache的autoindex模块(呃,我发现我用的wamp关掉这个模块apache就启动不了了- -!)。

补充:

经过一些实验,建议将.htaccess文件改成如下:

RewriteEngine On
# Redirect Trailing Slashes…
RewriteCond %{REQUEST_FILENAME} !-d #防止真实目录导致循环重定向
RewriteRule ^(.*)/$ /public/$1 [L,R=301]
# Handle Front Controller…
#RewriteCond %{REQUEST_FILENAME} !-d #防止用户直接打开真实目录
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]