Apache 的带有 PHP 标头的 mod_proxy_html("Location:...");不重定向

Posted

技术标签:

【中文标题】Apache 的带有 PHP 标头的 mod_proxy_html("Location:...");不重定向【英文标题】:Apache's mod_proxy_html with PHP header("Location:..."); doesn't redirect 【发布时间】:2013-02-12 12:54:28 【问题描述】:

我已经用谷歌搜索了这个问题的废话,但一无所获,所以希望你们能提供帮助。

目标 配置反向代理(使用 Apache 的 mod_proxy)以启用通过 Internet 访问内部 php 应用程序使用 mod_proxy_html 重写我的应用程序中的 URL。

问题描述 考虑仅使用以下代码的landing.php:

<a href="redirect.php">redirect.php</a>

和redirect.php只有:

<?php
    header("Location:http://internal.example.com/landing.php");
?>

使用我的 httpd.conf 中的这个 sn-p

UseCanonicalName On

LoadFile /usr/lib64/libxml2.so
LoadModule proxy_html_module modules/mod_proxy_html.so
LoadModule xml2enc_module modules/mod_xml2enc.so

<VirtualHost *:80>
    ServerName example.com

    <Proxy *>
            Order deny,allow
            Allow from all
            AllowOverride None
    </Proxy>

    ProxyPass / http://internal.example.com/
    ProxyPassReverse / http://internal.example.com/
    ProxyHTMLLinks a href #Commenting out this line fixes the problem, but I need it for rewriting
    ProxyHTMLEnable On
    RequestHeader unset Accept-Encoding
</VirtualHost>

当我转到http://example.com/landing.php 并单击“redirect.php”时,它应该带我回到landing.php 页面。相反,我在 Firefox 中收到“此连接已重置”,或在 Chrome 中收到“未收到数据”。 (仅供参考,转到http://internal.example.com/redirect.php 重定向正确。)

问题: 为什么重定向会通过反向代理失败,我该如何解决这个问题?

提示 我发现了一些可能有用的东西...

我知道如果我注释掉“ProxyHTMLLinks a href”,这将正常工作。但很明显,这是我需要的重写功能。

我还可以将redirect.php页面更改为以下,这可以正常工作:

<?php
    header("Location:http://internal.example.com/landing.php");
?>
random text

我猜这个文本会以某种方式对页面或 HTTP 标头产生一些影响,从而使 mod_proxy_html(或更具体地说是 ProxyHTMLLinks)的运行方式与没有它时不同。

我还可以将redirect.php页面更改为以下内容并让它工作:

<?php
    header("Location:http://internal.example.com/landing.php");
    header("Content-Type:");
?>

这是因为 ProxyHTMLLinks 默认只应用于 Content-Type 文本/html 文件。但是,我不想破解所有对 header("Location:...") 的调用来完成这项工作。我不介意更改对 header("Location:...") 的所有调用,假设我正在更改的是纠正问题,而不是创建 hack。

最后,我在反向代理服务器上进行了一些数据包嗅探,发现标头(“Location:...”)向反向代理服务器发送了 HTTP/1.1 302 Not Found,但它没有将其传递给请求redirect.php 的浏览器。当我尝试上述“解决方案”之一时,302 然后从反向代理服务器传递到请求redirect.php 的计算机。 我的理解是Location头应该去浏览器,然后浏览器应该请求传回的新位置。所以它失败了,因为 302 没有进入浏览器......

仅供参考,我已尝试查看错误日志以查看 mod_proxy_html 是否在某处失败,但我没有看到任何内容,尽管我愿意接受有关日志记录的具体建议,因为我不是 100%确定我是否正确设置了日志记录。

对不起,这太长了,只是想尽可能具体。 提前致谢!

【问题讨论】:

【参考方案1】:

我发现了问题所在。我需要在标头 Content-Type 中显式传递字符集才能使其正常工作。 这是通过添加:

AddDefaultCharset utf-8

到我的 Apache 配置文件。这全局修复了对 header("Location:...") 的所有调用,而无需向每个调用添加 header("Content-Type:") 或 header("Content-Type:text/html;charset=utf-8")其中之一。

简而言之,我所说的 mod_proxy_html 的 ProxyHTMLLinks 会导致 302 Found 无法从反向代理服务器转发到客户端,如果 a) 内容类型为 text/html(因此 ProxyHTMLLinks)适用,b ) 未设置字符集并且 c) 您的页面没有传回内容。

在我看来,这是正常情况。处理表单输入的页面通常满足所有三个条件。

可能出于某种原因,这是预期的功能,而我做错了其他事情,但我看不出那会是什么。至少这里有一个优雅的锻炼,以防万一有人觉得它有用。

【讨论】:

以上是关于Apache 的带有 PHP 标头的 mod_proxy_html("Location:...");不重定向的主要内容,如果未能解决你的问题,请参考以下文章

php 没有获取自定义标头(Apache 2.4 + FPM/FastCGI php 7)

Apache2 发送两个带有映射“nph-”CGI 的 HTTP 标头

PHP 标头未使用 litespeed 设置(但适用于 apache)

带有 PHP 标头的跨域请求标头 (CORS)

PHP API - Nginx 给了我无效的数据类型标头

带有 MIME 版本的 php 电子邮件标头:1.0