Apache 2重写规则错误地更改了URL

时间:2017-03-09 12:08:02

标签: apache .htaccess mod-rewrite apache2.4

请注意,这是我提出的上一个问题的重复。然而,它最初措辞严厉,编辑了很多次,几乎成了一个不同的问题,因此我决定提出一个新的问题

文件

我有以下文件:

example.dev.conf vhost文件

这是一个非常简单的vhost文件:

<VirtualHost *:80>
        ServerName example.dev
        ServerAlias *.example.dev
        DocumentRoot /var/www/example

        <Directory /var/www/example >
                AllowOverride All
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>

<VirtualHost *:443>
        ServerName example.dev
        ServerAlias *.example.dev 
        DocumentRoot /var/www/example

        <Directory /var/www/example >
                AllowOverride All
                Order allow,deny
                Allow from all
        </Directory>
</VirtualHost>

.htaccess

以下文件会将所有网址重定向到https等效网址,除非它以/api/开头。

还应该确保所有路由都使用index.php控制器。

RewriteEngine On

# Handle SSL
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/api/ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]

问题

这大部分都有效。

例如http://example.dev/blah重定向到https://example.dev/blah

但是,对于以/api/开头的任何内容,它似乎无法正常工作。

例如:http://example.dev/api/blah重定向到https://example.dev/index.php,而它根本不应该重定向!

请注意,如果删除htaccess文件的最后3行,重定向工作正常。

如何复制?

我发现有些人发现很难复制我的问题并坚持在某处有其他规则。因此,我决定尽我所能展示我的所有步骤,因此很容易复制:

vagrant init ubuntu/trusty64
vagrant up --provider virtualbox
vagrant ssh

sudo apt-get install apache2
sudo a2enmod rewrite

cd /etc/apache2/sites-available/
sudo touch example.dev.conf   
# copy contents of the example.dev.conf vhost file as seen above
sudo a2ensite example.dev.conf

cd /var/www/
sudo mkdir example
sudo chown -R www-data:www-data /var/www/example
sudo chmod 777 -R /var/www/example
cd example
echo "test" > index.php
touch .htaccess
# Copy contents of .htaccess file as seen above

sudo chown -R www-data:www-data /var/www/example
sudo chmod 777 -R /var/www/example

sudo service apache2 restart

3 个答案:

答案 0 :(得分:2)

其他两个答案都很好,但由于以下三个原因,我发布了另一个答案:

  1. Answer from Olaf:它适用于所有情况,除非用户直接在浏览器中输入http://domain.con/index.php。根据要求,除了以/api/开头的任何内容都应重定向到“https://
  2. Answer from YahyaEND标志仅在Apache 2.4+中受支持,因此这个答案对于面向类似答案的Apache 2.2上的某个人来说不起作用。
  3. POST请求应与307/308重定向,否则后期数据将丢失(请参阅下面的奥拉夫有用评论)。
  4. 为了使其适用于这两种情况,我建议使用THE_REQUEST而不是REQUEST_URI,因为REQUEST_URI在最后一次执行规则后会更改为/index.php

    RewriteEngine On
    
    # Handle SSL
    RewriteCond %{HTTPS} off
    RewriteCond %{THE_REQUEST} !\s/+api/ [NC]
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=308,NE]
    
    # Handle Front Controller...
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^ index.php [L]
    

答案 1 :(得分:1)

最有可能的是,/api/请求被重定向到https://example.dev/index.php的原因如下:

  • /api/...重写为index.php
  • index.php重定向到https://...

要了解这种情况发生的原因,请查看Query.filter()的工作原理。规则是按顺序尝试的,但是当重写发生时(图中的“URI更改?”),Apache再次以结果URI开始,直到不再进行重写。

为避免重定向到https://...的{​​{1}},您还必须排除/api/作为第一条规则,例如

index.php

答案 2 :(得分:1)

我想我设法解决了这个问题。

在阅读本文时:http://httpd.apache.org/docs/current/rewrite/flags.html#flag_l结果表明最后一个标志并不意味着不再使用其他规则。

例如,对于以下文件:

RewriteEngine On

# Handle SSL
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/api/ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=308]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [L]
  • /api/blah被重写为index.php
  • 然后再次通过所有规则。根据文档,这可能由于以下原因而发生:
  

当处理重写请求时,可能会再次遇到.htaccess文件或部分,因此可以从头开始再次运行规则集。最常见的情况是,如果其中一个规则导致重定向(内部或外部)导致请求进程重新开始,则会发生这种情况。

  • index.php然后匹配第一条规则,以便创建重定向到https://example.dev/index.php

解决方案是使用END flag(正如@anubhava所提到的,仅在Apache 2.4+中支持),以防止重新处理规则。

所以解决方案如下:

RewriteEngine On

# Handle SSL
RewriteCond %{HTTPS} off
RewriteCond %{REQUEST_URI} !^/api/ [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R]

# Handle Front Controller...
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [END]

现在我去http://example.dev/api/blah

  • 将其重写为index.php
  • 由于它具有END规则,因此不再处理规则!
  • 因此http://example.dev/api/blah保持原样,并根据需要使用index.php控制器。

感谢@Olaf Dietsche让我走上正轨并建议308重定向!