为什么RewriteCond%{SCRIPT_FILENAME}!-d打破了我的RewriteRule

时间:2014-12-02 22:38:23

标签: apache .htaccess mod-rewrite

我的.htaccess看起来像这样:

Options -Indexes

RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.html [L]

如果我访问www.myhost.com,我会收到302 Moved Temporarily响应,将我重定向到www.myhost.com/index.html。

如果我注释掉.htaccess文件的一个特定行,如下所示:

Options -Indexes

RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
#RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.html [L]

我访问www.myhost.com,我得到了200 OK,我看到www.myhost.com/index.html的内容,但URL只显示www.myhost.com

我的问题:为什么第一个版本的行为方式如此?我原本期望两个版本的行为与第二个版本的行为方式相同。

特别是,我将行RewriteCond %{SCRIPT_FILENAME} !-d解释为:如果相对URL不是目录,则应用规则。因此,如果我调用www.myhost.com,SCRIPT_FILENAME应该是一个空字符串,这个空字符串既不应该作为文件也不应该作为目录,并且该规则应该适用,将index.html附加到我的主机URL的根目录。

我错过了什么?

编辑[2014-12-03] 为了给你一些背景知识,我想在URL中隐藏index.html但显示其内容。这是一个简单的单页网站,有css,js,图像,也许还有一些php。 虽然我有兴趣听听你如何解决这个问题,但这篇文章中的问题并不是如何解决它,而是要了解RewriteCond如何使用-d参数。

编辑[2014-12-06] 在下面发布不同的解决方案后,让我试着解释一下我的想法:

  1. 我假设SCRIPT_FILENAME的空字符串确实被解释为目录,即根目录。因此,RewriteRule从未踢过。
  2. 对/index.html进行了某种302重定向。我现在无法重现它,所以我真的不确定是什么造成的。

4 个答案:

答案 0 :(得分:3)

mod_rewrite总是很棘手

首先要考虑的是,还有其他默认设置和配置可能导致您的第二个问题,/css/的请求被定向到/index.html http://httpd.apache.org/docs/2.0/misc/rewriteguide.html

  • 如果/css/不存在,或者不允许访问,则可能与!-d条件匹配。
  • 由于这是.htaccess,并且这些是继承的,因此很可能匹配第一个条件(空请求)。

您的.htaccess已调整:

Options -Indexes

RewriteEngine On

RewriteRule ^$ index.html [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^/index.html$
RewriteCond %{REQUEST_URI} ^/.+$
RewriteRule ^.+$ index.html [L]

现在,只要/css/目录存在,你应该没问题。

答案 1 :(得分:1)

我试过这个,但仍然遇到问题(见下面的评论):

Options -Indexes

RewriteEngine On

RewriteBase /
RewriteRule ^$ index.html [L]

RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.+$ index.html [L]

我对此的理解如下:

  1. Options -Indexes:阻止在浏览器中自动显示目录内容
  2. RewriteEngine On:确保mod_rewrite处于活动状态
  3. Rewrite Base /RewriteRule中使用的路径将相对于root / host进行解释(我认为这也是默认行为)
  4. RewriteRule ^$ index.html [L]:如果相对路径(在主机名之后)是空字符串,则显示index.html。
  5. [L]表示这是此块的最后一个RewriteRule。
  6. RewriteCond %{REQUEST_FILENAME} !-f:如果没有与相对路径具有相同名称/路径的文件,(AND ...)
  7. RewriteCond %{REQUEST_FILENAME} !-d:...如果此外没有与相对路径具有相同名称/路径的目录,则应适用以下RewriteRule
  8. RewriteRule ^.+$ index.html [L]:如果相对路径不是空字符串,则显示index.html。
  9. 编辑[2014-12-06] 这个解决方案的问题: 如果我输入www.myhost.com/asdf/我正在获取www.myhost.com/index.html的内容,但没有任何样式或图像。经过进一步分析,我发现所有css,js和图像文件都是相对于新的基本路径加载的,如/ asdf / css / *。当然,它找不到任何这些资源。所以它看起来像这里应用的第二条规则。 asdf /既不是现有目录也不是现有文件名,也不是空字符串,所以我看到了index.html的内容,但所有资源都是相对于/ asdf /加载的。

答案 2 :(得分:1)

我终于找到了现在似乎更符合逻辑的解决方案:

Options -Indexes

RewriteEngine On
RewriteRule ^$ index.html [L]

ErrorDocument 403 /403.html
ErrorDocument 404 /404.html

我没有尝试将所有可能的路径重新路由到index.html,而是创建了一个403.html和404.html页面并按预期使用它们。

如果我访问www.myhost.com,我会看到www.myhost.com/index.html的内容。
如果我访问www.myhost.com/css/这样的有效目录,我会看到403.html文件的内容。
如果我访问www.myhost.com/invalidpath这样的无效路径,我会看到404.html文件的内容。

答案 3 :(得分:0)

您可以使用:

Options -Indexes

RewriteEngine On
RewriteBase /
RewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^.+$ index.html [L]

在这种情况下,只有当它不是空字符串时才会出现。