htaccess无声重定向到子目录:子目录显示何时没有尾随'/'

时间:2011-11-08 05:12:59

标签: apache .htaccess mod-rewrite

我在谷歌和StackOverflow周围挖掘高低,试图找出我的问题,尝试无数的解决方案,但没有任何完全有效。

我希望将服务器上主域的Web根目录移动到子目录。我目前用于Web根目录的服务器路径:

/home/user/public_html/MyWebFilesHere

我期待的是:

/home/user/public_html/subdir/MyWebfilesHere

当我浏览mydomain.com时,应该没有明显的区别(即重定向后“subdir”不可见)。

不幸的是,我仅限于使用.htaccess文件执行此操作,因为我在共享主机上并且无法访问Apache配置文件等。 :(

我目前在public_html的.htaccess中拥有的是:

RewriteEngine on
RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
RewriteCond %{REQUEST_URI} !^/subdir/
RewriteRule ^(.*)$ /subdir/$1 [L]

这成功地将所有查询重定向到子目录,但是有一个非常奇怪的问题。如果我去

mydomain.com/Contact/

它工作得很好,将查询重定向到路径/ subdir / Contact /但只留下地址栏。如果我去

mydomain.com/Contact

(注意缺少尾随'/'),地址栏中显示的是

mydomain.com/subdir/Contact/

这不是我想要的,因为“subdir”正在显示。

有关我实际网站上的工作示例,请尝试浏览

colincwilliams.com/Contact/

比较
colincwilliams.com/Contact

你们有没有关于如何使用和不使用尾部斜线进行静默工作的想法?

2 个答案:

答案 0 :(得分:7)

这可能发生了,因为mod_dir(如果对目录的请求缺少对同一个的尾随斜杠的一个尾部斜杠,则自动重定向浏览器的模块。请参阅{{3} }

发生的事情是:

  1. 您要求:mydomain.com/Contact
  2. 由于/Contact不是目录,因此
  3. mod_dir不会触及此内容
  4. /Contact被重写为/subdir/Contact内部被重定向
  5. mod_dir发现/subdir/Contact是一个目录并且缺少尾部斜杠,因此将浏览器重定向到mydomain.com/subdir/Contact/
  6. 现在,您的浏览器的位置栏中包含/ subdir /。
  7. 您可以在.htaccess中添加DirectorySlash off以关闭重定向的mod_dir。但是,如果您希望目录具有尾部斜杠,则可以为其添加单独的条件。根据您已有的内容,我们可以将其扩展到:

    RewriteEngine on
    
    # Has a trailing slash, don't append one when rewriting
    RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
    RewriteCond %{REQUEST_URI} !^/subdir/
    RewriteCond %{THE_REQUEST} ./\ HTTP/1\.[01]$ [OR]
    # OR if it's a file that ends with one of these extensions
    RewriteCond %{REQUEST_URI} \.(php|html?|jpg|gif|css)$
    RewriteRule ^(.*)$ /subdir/$1 [L]
    
    # Missing trailing slash, append one
    RewriteCond %{HTTP_HOST} ^(www\.)?mydomain\.com$
    RewriteCond %{REQUEST_URI} !^/subdir/
    RewriteCond %{THE_REQUEST} [^/]\ HTTP/1\.[01]$
    # But only if it's not a file that ends with one of these extensions
    RewriteCond %{REQUEST_URI} !\.(php|html?|jpg|gif|css)$
    RewriteRule ^(.*)$ /subdir/$1/ [L]
    

    注意:我将!^/mydomain/更改为!^/subdir/,认为这是一个拼写错误,因为如果没有它,mod_rewrite将无限循环内部(foo - > / subdir / foo - > / subdir / subdir / foo - > / subdir / subdir / subdir / foo等)。如果我弄错了,你可以改回来。

    编辑:查看我添加的RewriteCond与\.(php|html?|jpg|gif|css)的匹配项。这些是在不添加尾部斜杠的情况下传递的文件扩展名。您可以添加/删除以满足您的需求。

答案 1 :(得分:0)

Jon Lin的回答非常有助于确定在我非常相似的设置中导致问题的原因。为了完整起见,我将在其答案中包含相关信息:

  

这可能是因为mod_dir(如果对目录的请求缺少带有斜杠的同一事物的尾部斜线,则自动重定向浏览器的模块。请参阅DirectorySlash directive in mod_dir

     

发生了什么:

     
      
  1. 您要求:mydomain.com/Contact
  2.   
  3. mod_dir没有触及这个,因为/Contact不是目录
  4.   
  5. /Contact被重写为/subdir/Contact并在内部重定向
  6.   
  7. mod_dir发现/subdir/Contact是一个目录并且缺少尾部斜杠,因此它将浏览器重定向到mydomain.com/subdir/Contact/
  8.   
  9. 现在,您的浏览器的位置栏中包含/ subdir /。
  10.   

在我的情况下,我有一些请求被重定向到/subdir,但有一些例外,并且不想为每个例外重新启用DirectorySlash。

通过在初始重定向到/subdir后允许RewriteEngine继续,可以在mod_dir看到它之前模拟mod_dir在做同时考虑/subdir的情况。

RewriteEngine on

RewriteCond %{REQUEST_URI} !^/exception1|exception2|...
RewriteRule ^(.*)$ /subdir/$1

RewriteCond %{REQUEST_FILENAME} -d
RewriteCond %{REQUEST_URI} !(.*)/$
RewriteRule ^subdir/(.*) $1/ [R,L]

注意:如果有其他规则,您可能需要注意允许RewriteEngine继续。与第二条规则不匹配将继续执行可能产生不同结果的任何进一步规则。

如果重定向到/subdir,则使用第三条规则停止RewriteEngine处理可以避免这种情况:

RewriteCond %{REQUEST_URI} ^subdir
RewriteRule .* - [L]