.htaccess htaccess中的循环重定向:HTTPS->;HTTP规则被忽略

.htaccess htaccess中的循环重定向:HTTPS->;HTTP规则被忽略,.htaccess,mod-rewrite,https,openshift,haproxy,.htaccess,Mod Rewrite,Https,Openshift,Haproxy,第一部分 我在htaccess文件(在OpehShift服务器上)中有以下重写规则: 其目的是通过SSL处理一些路径,而所有其他路径都应该可以通过普通http访问。最初,设置这样的配置是一个挑战,但最终解决了——您可以在上找到它的历史记录 在过去的某个时刻(可能是某个OpenShift更新)之前,它一直运行良好,当时它开始在https页面上循环:例如,当用户在其个人资料页面上(使用https)并在安全路径外单击页面链接时,它会一次又一次地尝试重定向到https 根据规则,如果不是登录、注册、配置

第一部分

我在htaccess文件(在OpehShift服务器上)中有以下重写规则:

其目的是通过SSL处理一些路径,而所有其他路径都应该可以通过普通http访问。最初,设置这样的配置是一个挑战,但最终解决了——您可以在上找到它的历史记录

在过去的某个时刻(可能是某个OpenShift更新)之前,它一直运行良好,当时它开始在https页面上循环:例如,当用户在其个人资料页面上(使用
https
)并在安全路径外单击页面链接时,它会一次又一次地尝试重定向到
https

根据规则,如果不是登录、注册、配置文件或验证码页面,他们应该将
https
更改为
http
,但这种情况不再发生。有什么问题吗?提前谢谢

第二部分

尽管事实上我接受了@anubhava的答案(因为这似乎是Apache的问题,而不是我的问题,正如他在几个小时的宝贵调试后所认为的那样),我仍然在与这个问题作斗争,任何进一步的解决方案/变通办法都受到高度欢迎

同时,问题被精确定位到以下代码:

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ - [env=ps:https]

RewriteCond %{HTTP:X-Forwarded-Proto} https
RewriteRule ^(.*)$ - [env=ps:http]

# known public pages
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} ^/site/page/about
RewriteRule (.*) %{ENV:ps}://%{SERVER_NAME}/$1?ps=%{ENV:ps}&step=1 [last,redirect=permanent]
现在,当我转到about页面时,我得到了以下http头:

HTTP/1.1 301 Moved Permanently
Date: Thu, 27 Nov 2014 15:07:27 GMT
Server: Apache/2.2.15 (Red Hat)
Location: https://mydomain.rhcloud.com/site/page/about?ps=http&step=1
Content-Length: 385
Content-Type: text/html; charset=iso-8859-1
Accept-Ranges: none
Keep-Alive: timeout=15, max=99
Connection: Keep-Alive
请注意,
Location
https
proto,而
ps
参数输出为
http
(如预期)。如果这两个值都取自
ps
变量,情况会如何?看起来怪怪的

简而言之:从https重定向到http在OpenShift服务器上不起作用。尽管规则规定协议应该是
http
服务器发送
https
——因此循环重定向

第三部分

也许我应该提到OpenShift站点使用HAProxy作为前端。其配置不包含任何特定于ssl的设置。但我发现,人们可能会读到:

最后,无法将人们从HTTPS连接中转移出去,这被认为是不安全的,不受支持


所以,对于从安全页面进行的重定向,HAProxy是否总是隐式地将协议覆盖到
https
?那么如何解决这个问题呢?

使用
请求,而不是
请求URI
因为您使用的是前端控制器

RewriteEngine on

# Must NOT be SSL
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{HTTP:X-Forwarded-Proto} =https
RewriteCond %{THE_REQUEST} !\s/+user/(login|register|profile|captcha) [NC]
RewriteRule ^ http://%{SERVER_NAME}%{REQUEST_URI} [L,R=301,NE]

# MUST be SSL
RewriteCond %{HTTP:X-Forwarded-Proto} !=https
RewriteCond %{THE_REQUEST} \s/+user/(login|register|profile|captcha) [NC]
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [L,R=301,NE]

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule . index.php

最后,我设法建立了一个变通办法,尽管我认为它并不优雅。如果你知道另一种方法,请告诉我。我指的是在OpenShift环境中工作的方式

解决方案是使用
.htaccess
仅处理单向重定向:从
http
https
。从
https
http
的重定向由客户端代码处理,该代码指示浏览器在不同的方案下重新加载页面

.htaccess

RewriteEngine on

# MUST be SSL
RewriteCond %{HTTP:X-Forwarded-Proto} !https 
RewriteCond %{THE_REQUEST} \s/+user/(login|register|profile|captcha)
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=302,NE]

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php 
RewriteRule . index.php
index.php

...
require('switchhttp.php');
...
<?
function redirect_url($url)
{
  ?>
  <script>
  window.location.href="<? echo $url; ?>";
  </script>
  <?
}

$urls = array("/user/login", "/user/register", "/user/captcha", "/user/profile");
$url = rawurldecode($_SERVER['REQUEST_URI']);

if(!in_array($url, $urls) && isset($_SERVER['HTTPS']))
{
  redirect_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
  exit;
}
?>
switchhttp.php

...
require('switchhttp.php');
...
<?
function redirect_url($url)
{
  ?>
  <script>
  window.location.href="<? echo $url; ?>";
  </script>
  <?
}

$urls = array("/user/login", "/user/register", "/user/captcha", "/user/profile");
$url = rawurldecode($_SERVER['REQUEST_URI']);

if(!in_array($url, $urls) && isset($_SERVER['HTTPS']))
{
  redirect_url("http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]");
  exit;
}
?>

window.location.href=“”;
这对我有用

此外,我可能应该警告那些可能感兴趣的人,OpenShift gears可能会意外地进入“缓存状态”(可以这么说,这可能与HAProxy有关)。在这种情况下,更新gears上的文件不会生效-您的浏览器,无论是否清除了缓存,甚至全新连接的客户端也会接收旧页面。调试非常令人沮丧。到目前为止,我发现解决这个问题的唯一方法就是重新启动你的装备。

谢谢你的回答,但是你的代码破坏了CSS样式。我将尝试仅使用_请求。在我的原始代码中使用
_请求
而不是
请求
并不能解决无限重复问题。确定请参阅更新的规则以解决css问题。如果导致重定向循环,则打开
https://domain.com/user/profile
URL在Chrome开发工具或Firebug中,并查看在
Net
选项卡中获得的重定向。它现在保留样式,但当用户单击主页链接(
/
地址)时,它会获得带有
https
的主页,这是不正确的。此外,所有其他公共页面(例如
/site/page/about
)都试图使用
https
进行显示,但由于循环重定向而失败。感谢您在聊天中提供的帮助。当我们发现openshift gears似乎忽略了https值,或者没有将其传递给php时,我的天哪,您必须采取php路线来完成它。希望openshift能做出回应+很奇怪,维基百科上个月似乎使用了同样的方法:当我在谷歌搜索结果导航后第一次打开一篇文章时,我看到了它的
http
版本,然后页面会自动在
https
下重新加载。OpenShift支持部门刚刚确认了我的建议,免费计划用户的所有技术问题都应该发布在StackOverflow上。这很奇怪,显然他们的支持人员什么都不知道。