根据当前的HTTP规范,除了特定的几个例外情况,
304 Not Modified
响应不应该返回实体头。引用自
RFC 2616第10.3.5节:
如果有条件的GET使用了强缓存验证器,则响应SHOULD NOT包括其他实体头。
否则(即有条件的GET使用了弱验证器),响应MUST NOT包括其他实体头;这可以防止缓存实体主体和更新的头之间的不一致。
不幸的是,所有扩展头都被
归类为实体头。
然而,展望未来,在旨在取代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)时,上述标头列表是唯一允许通过的标头(除了一些自动生成的标头,如Date和Server)。从我所看到的情况来看,似乎没有一种简单的方法来钩入此代码以改变行为。
底线是,在目前的Apache版本中仍然不可能实现。至少有一个错误报告要求支持其他标头,但那是特别针对CORS标头的。但带着一点运气,这可能会鼓励他们更加开放地支持自定义标头。
但在此之前,我唯一能建议的解决方案是自己修补服务器。如果您不想重新构建源代码,甚至可以直接修补二进制文件。例如,如果您只需要支持一个或两个新标头,则可以替换一些您不太可能使用的现有标头(例如已过时的Set-Cookie2)。
只需在Apache bin目录中搜索要替换的标题名称(在Windows上,您应该在libhttpd.dll中找到它们)。然后使用二进制编辑器将空终止字符串替换为您的新标题名称(当然,它需要与您正在替换的标题相同长度或更短)。
我不知道其他操作系统的情况,但我已经在Windows上测试过了,它确实可以工作。显然,这是一个可怕的黑客方式,但如果您足够绝望,您可能会考虑这个选项。