Apache在发送304响应时忽略了PHP头信息

6

当我在Apache + mod_php5中设置自定义头时,这个功能非常好用:

header('Foo: Bar');

但是,当我尝试在发送304未修改响应的同时执行此操作时,Apache似乎已经删除了头信息(包括X-Powered-By和其他标准头信息)。
header('HTTP/1.1 304 No Content');
header('Foo: Bar');

有人知道如何解决这个问题吗?


我不太确定如何阅读这个RFC。也许Apache删除头以符合RFC(并帮助缓存管理器)?也许你可以理解它? - jensgram
我相当了解RFC,并且它并没有强制限制。它确实提到某些标头应该存在(主要是与缓存相关的标头)。在我的情况下,我需要添加CORS标头,以进行跨域访问。 - Evert
尝试使用以下代码替换2:header('Foo: Bar', true, 304);。至于“头似乎被Apache删除了” - 您需要显示您的Apache配置(httpd.conf,您的<VirtualHost>以及.htaccess - 这些指令可以放在任何地方)。 - LazyOne
LazyOne:尝试使用header()语法会导致相同的问题。至于配置,我在Ubuntu上使用100%默认配置,既没有虚拟主机也没有.htaccess文件。我认为值得注意的是,即使X-Powered-By也被删除了。我知道你的名字是懒惰,但请在自己的系统上尝试一下,我相信你会看到相同的情况。 - Evert
@Evert 如果在php.ini中设置了expose_php = Off,PHP本身可能根本不会发送X-Powered-By。至于304 - 在我的初始评论之后,我重新运行了几个测试,并且是的 - 自定义标头已被删除,但对于404和其他非3xx代码(使用302、303、305、306进行检查)则存在。必须是针对304特定优化(304 =未修改),其中响应正文必须尽可能小。 - LazyOne
是的,我刚刚添加了关于 X-Powered-By 的注释,因为它在 304 中被特别删除了。这是我第一个指示这是 Apache 所做的。不过还是谢谢你的检查 =) - Evert
4个回答

3
这是否回答了问题?
如果条件GET使用强缓存验证器(参见13.3.3节),则响应不应包括其他实体标头。否则(即,条件GET使用了弱验证器),响应不能包括其他实体标头;这可以防止缓存的实体主体与更新后的标头之间出现不一致。
来源:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5

3
我不确定CORS头部(这是我实际尝试的内容)是否被认为是“实体头部”,但无论如何,我希望能够添加任何其他头部。具体来说,我需要CORS头部以避免浏览器错误。因此,它并没有回答我的问题,因为它并没有解决我的问题。 - Evert
@Evert 或许您可以更新一下您的问题,提到您正在发送CORS标头(我在评论中看到了)。另外,您遇到了什么浏览器问题呢?对我来说,您似乎正在尝试做一些不可能的事情,并且被Web服务器阻止了。 - Ben
这是关于Firefox 5的,但那有点离题了。我关心的是能够设置自定义标头,同时发送回304状态代码。HTTP规范中没有任何阻止这样做的内容。 - Evert
@Evert 未被识别的头部将被视为实体头部。http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html - Ben
它们可能被视为实体头,但规范也表示应该删除,而不是必须删除。但是除此之外,我真的不关心规范;我只想修复我的错误 ;) - Evert
@Evert 在你的代码中,你是否总是希望额外的头部是 Foo: Bar,还是该值会动态更改?如果不是,我已经成功实现了它。由于某种原因,即使发送 304,我也有 X-Powered-By。 - Ben

3
截至今天为止(据我所知),Apache 2.4.23是最新版本,当你发送304“未修改”响应时,你将无法避免这个问题,因为Apache确实会明确删除所有非白名单头文件。

http://svn.apache.org/viewvc/httpd/httpd/tags/2.4.23/modules/http/http_filters.c?view=markup#l1331

所以,无论我们是否喜欢它(因为我也遇到了Apache从响应中删除我的CORS头部当我发送304的情况),看起来Apache确实遵循RFC建议,并将所有不在该列表之内的内容视为实体头部。

一种解决方案是修补Apache源代码以扩展该列表并转向部署您自己的软件包到服务器,但这肯定不是没有自己的长列表的影响。另一方面,我听说nginx没有这个问题。

我提供的内容将被标准浏览器中的WebGL运行时等消费,因此如果它们对我的304响应中缺乏CORS表示抱怨,我将不得不将所有内容转换为200 OK并放弃带宽节省。


0
我用一个技巧来解决这个问题: 1. 在304头之前放置所有头文件 2. 在发送304之前刷新这些头文件
header('Foo: Bar');
flush();
header('HTTP/1.1 304 No Content');

只有在找到304之前,Apache才不会删除任何标题。 在发送304之前,我们通过flush()强制发送其他标题。 那个Apache不能伤害我。


这会导致状态码200和“警告:无法修改头信息 - 头已经发送”。 - Jarda Pavlíček

-1

尝试:

header('Foo: bar', true, 304);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接