<VirtualHost *:80>
ServerAdmin webmaster@dev.dom.com
DocumentRoot "C:/Program Files/Apache Software Foundation/Apache2.2/htdocs"
ServerName dev.dom.com
ServerAlias dev.dom.com
ErrorLog "logs/dev.dom.com-error.log"
CustomLog "logs/dev.dom.com-access.log" common
PassEnv CLUSTER
Header always set X-Cluster "%{CLUSTER}e"
</VirtualHost>
这是我的配置。我有一个环境变量,它告诉我我在哪个集群上,它在"X-Cluster"中作为标头传递。这在 200 或 404 响应上返回正常,但 304 未修改响应永远不会返回标头,即使它返回其他适当的 Apache 标头也是如此。
如何在 304 响应期间设置标头?
根据当前的HTTP规范,304 Not Modified
响应不应该返回实体标头(除了一些特定的异常)。引用 RFC 2616 的第 10.3.5 节:
如果条件 GET 使用强缓存验证器,则响应不应包含其他实体标头。否则(即条件 GET 使用弱验证器),响应不得包含其他实体标头;这可以防止缓存的实体正文和更新的标头之间的不一致。
不幸的是,所有扩展标头都被归类为实体标头。
然而,展望未来,在旨在取代RFC 2616的HTTPbis规范草案中,规则要宽松得多。引用条件请求规范的第 4.1 节:
由于 304 响应的目标是最大限度地减少信息传输当收件人已有一个或多个缓存表示形式时,一个发送方不应生成除上面列出的字段,除非所述元数据出于以下目的而存在指导缓存更新。
因此,如果您要设置一个不会被归类为表示元数据的自定义标头,那么我希望根据新规则将其视为合法。
也就是说,无论这些规范中写了什么,你仍然需要处理Apache可以支持的内容。从我在源代码中看到的内容来看,304 响应仍然不支持自定义标头。
过滤标头的位置位于文件/modules/http/http_filters.c 中的 ap_http_header_filter 函数中:
更具体地说,此代码:
if (r->status == HTTP_NOT_MODIFIED) {
apr_table_do((int (*)(void *, const char *, const char *)) form_header_field,
(void *) &h, r->headers_out,
"Connection",
"Keep-Alive",
"ETag",
"Content-Location",
"Expires",
"Cache-Control",
"Vary",
"Warning",
"WWW-Authenticate",
"Proxy-Authenticate",
"Set-Cookie",
"Set-Cookie2",
NULL);
}
返回"未修改"响应 (304) 时,上面的标头列表是唯一允许通过的标头列表(除了一些自动生成的标头,如日期和服务器)。据我所知,似乎没有一种简单的方法来挂钩到此代码中来改变行为。
最重要的是,目前这在Apache中仍然是不可能的。至少有一个错误报告请求支持其他标头,但这是专门针对 CORS 标头的。不过,如果运气好的话,这可能会鼓励他们更愿意支持自定义标头。
但在此之前,我能建议的唯一解决方案是自己修补服务器。如果您不想从源代码重建,甚至可以直接修补二进制文件。例如,如果您只需要支持一两个新标头,则可以替换一些您不太可能使用的现有标头(例如 Set-Cookie2,无论如何它已经过时了)。
只需在 Apache bin 目录中搜索要替换的标头名称(在 Windows 上,您应该在 libhttpd.dll 中找到它们)。然后使用二进制编辑器将以 null 结尾的字符串替换为新的标头名称(当然,它需要与要替换的标头长度相同或更短)。
我不知道其他操作系统,但我已经在 Windows 上测试过,它似乎确实有效。这显然是一个可怕的黑客,但如果你足够绝望,你可能会认为这是一种选择。
Apache 明确禁止修改 304 响应中的响应标头以符合 http 规范。 此类响应的名称为"未修改"。 您可以使用 Apache 的过滤器架构、编写自定义模块或 mod_perl 来修改此行为,但这很可能是错误的做法。