2011-06-27 46 views
12

我想弄清楚最好的HTTP标头发送四个用例。我希望拿出不依赖于用户代理/协议版本嗅探的头文件,但我会接受,如果没有其他适合。所有URL都通过完全自定义处理程序获取,因此我可以根据需要选择所有标题,这全部是关于中间代理和用户代理。如果可能的话,这应该与HTTP/1.0和HTTP/1.1客户端兼容。如果存在多种解决方案,通过电线发送时最好的解决方案将是最短的解决方案。HTTP头:控制缓存和历史机制

静态公共内容

所有“静态公共含量”的东西,HTTP的真正意义:如果URL是一样的,内容是一样的。我可以轻松地做到这一点:例如,我将用户配置文件图标放入http://domain.com/profiles/xyz/icon/1234abcd,其中“1234abcd”是图标文件内容的SHA-1。如果我将来更改为图标,我将创建一个新的URL并修改所有应该使用新图标的现有推荐人。什么是最好的头文件来声明这可能会永久缓存并可能被共享?我目前正在思考一些问题:

Date: <current time> 
Expires: <current time + one year> 

这是否足以允许用户代理和代理进行缓存?我需要Last-Modified还是Pragma

静态非公开内容

所有“静态非公开内容”的东西,是静态的,但可能无法提供给大家。实际上,这些内容仅对选定的登录用户可用(会话保持会话cookie保持会话UUID)。如果URL相同,则内容相同。但是,回应并不公开。用例可以是社交网络服务中选定好友共享的图片。我目前在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=<huge number>, s-maxage=0 

这足以让用户代理缓存和禁用代理吗?我需要Pragma吗?

挥发公开内容

所有“挥发性公开内容”的东西,易挥发,提供给大家。类似于http://slashdot.org/的首页,当未登录时。意图是允许快速更新不变URL中的内容。 请注意,我不想破坏用户代理历史机制(即,从易失性页面中单击某些内容,然后点击后退按钮不应导致从服务器获取易失性页面 - 但是,请单击一个链接去首页应该从服务器获取资源)。我目前正在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: public, max-age=0, s-maxage=0 

这足以防止缓存但允许历史机制(后退按钮)?我知道,如果我发送Cache-Control: no-store, must-revalidate我可以强制重新加载,但这不是我想要的,因为这也会打破后退按钮。我需要Last-Modified还是Pragma

尽管这是公开的,但允许中间代理缓存此内容可能没有意义,因为它是不稳定的。

挥发性非公开内容

所有“挥发性非公开内容”的东西,易挥发,不提供给大家(私人)。类似于登录时的http://slashdot.org/的头版。意图是允许快速更新不变URL中的内容。 请注意,我不想破坏用户代理历史机制(即,从易失性页面中单击某些内容,然后点击后退按钮不应导致从服务器获取易失性页面 - 但是,请单击一个链接去首页应该从服务器获取资源)。我目前在思考:

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=0, s-maxage=0 

这足以防止缓存但允许历史机制(后退按钮)?我需要Pragma吗?


的事情,还需要我的建议的首部测试:

  • 验证私人内容将无法通过HTTP/1.0代理被泄露。
  • 验证缓存在代理中是否正常工作。
  • 确认缓存在用户代理中正常工作。
  • 验证用户代理历史记录机制在用户代理(所有情况下)中工作。
  • 验证在链接到易失性页面后,从服务器获取新鲜内容。
  • 使用HTTPS而非HTTP验证所有结果。
+0

我知道以前的类似问题在http://stackoverflow.com/questions/2970938/ideal-http-cache-control-headers-for-different-types-of-resources - 但是,这是缺少三个重要的难题:后退按钮行为,用户代理兼容性和HTTP/1.0代理支持。 –

+0

另一个经常引用的来源http://www.mnot.net/cache_docs/也受到不处理现实世界的用户代理行为与后退按钮和HTTP/1.0代理支持。 –

+0

这里有一篇关于缓存控制的文章:http://palisade.plynt.com/issues/2008Jul/cache-control-attributes/ - 也缺少真实世界的后退按钮行为,用户代理兼容性和HTTP/1.0代理支持。 –

回答

10

我会回答,会发生什么我自己的问题:

静态公共内容

Date: <current time> 
Expires: <current time + one year> 

理由:这是与HTTP/1.0代理和RFC 2616第14节兼容:http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.21 Last-Modified标头对于正确的缓存不是必需的(因为符合标准的用户代理遵循Expires标题),但可能包含在最终用户消费中。如果用户点击重新加载/刷新按钮,包括Last-Modified标题也可能会减少服务器数据传输。如果添加了Last-Modified标题,它应该反映真实的数据而不是发明的东西。如果您想减少服务器数据传输(如果用户点击重新加载/刷新按钮)并且不能包含真实的标头,则可以添加ETag标头以允许有条件的GET(http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26)。如果您已经包含Last-Modified也加入ETag只是浪费。请注意,Last-Modified显然更好,因为它也支持HTTP/1.0客户端和代理。对于动态页面,ETag的合适值是页面/资源内容的SHA-1。请注意,使用Last-ModifiedETag将无助于服务器负载,只能使用服务器传出互联网管道/数据传输速率。

静态非公开内容

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=31536000, s-maxage=0 
Vary: Cookie 

理由:DateExpires头对于HTTP/1.0的兼容性和因为有指定的响应是私人没有明智的方法,这些标题传达的响应可能不会被缓存。 Cache-Control标头表明此响应可能会被私有缓存缓存,但共享缓存可能不缓存该响应。 s-maxage=0被添加,因为private可能不支持所有代理支持Cache-Controlhttp://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3 - 我不知道哪个代理被破坏)。 max-age设置为60*60*24*365(1年)的值,因为HTTP/1.1规范没有定义这个参数的任何上限,我想这是依赖于实现的。 Expires头将在未来限制为一年,所以在这里使用相同的逻辑应该没问题。 Vary: Cookie标头是必需的,因为用于检查访问者是否被允许查看内容的会话在cookie中传输;因为返回的响应取决于cookie值,所以如果cookie头被更改,则缓存可能不会使用缓存响应。

我可能会亲自打破最后一部分。通过不包含Vary: Cookie标题,我可以提高缓存的质量。例如:我有一个档案图像http://domain.com/icon/12,这个档案图片只会返回给选定的认证用户。我有一个访问者X,会话ID为5f2,我允许该用户的图像。访问者X注销,然后再次登录。现在X的会话ID为2e8存储在他的会话cookie中。如果我有Vary: cookie,则用户代理X不能使用缓存图像,并且强制将其重新加载到其缓存中。由于内容因Cookie而异,因此无法使用具有上次修改时间的条件GET。我还没有测试在这种情况下使用ETag是否有帮助,因为在这种情况下,服务器响应将是相同的(匹配从响应内容计算的SHA-1 ETag)。需要警告的是,Internet Explorer(至少是版本9)总是强制条件GET包含Vary: Cookie(来源:http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx)的资源。这是因为MSIE的内部缓存实现不记得它第一次发送哪个Cookie,因此无法知道当前Cookie是否是同一个Cookie。

但是,下面是一个由于丢失Vary: Cookie标题而导致的问题示例,以说明为什么确实需要技术上正确的行为。看看上面的例子,想象一下,在X退出之后,访问者Y用相同的用户代理登录(用户代理可能已经在X和Y之间重新启动,这没关系)。如果Y查看包含指向http://domain.com/icon/12的链接的页面,则Y会在页面内嵌入图标,即使Y以前没有使用过相同的用户代理,Y也无法看到该图标。在我的情况下,我不认为这是一个足够大的问题,因为Y可以通过检查用户代理缓存手动访问图标,无论可能添加Vary: Cookie。但是,这个问题可能会阻止Y注意到他不会在技术上访问此内容(这可能很重要,例如,如果Y是共同创作内容的话)。如果内容被认为是敏感的,服务器必须发送no-store,而不管这个Cache-Control指令引起的问题。

此处,添加Last-Modified标题将有助于用户点击重新加载/刷新按钮(请参阅上面的讨论)。

挥发公开内容

Date: <current time> 
Expires: <current time> 
Cache-Control: public, max-age=0, s-maxage=0 
Last-Modified: <real-last-modification-time> 

理由:告诉HTTP/1.0客户端和代理这种反应,应立即认为是过时的。包含Last-Modified时间以允许在资源再次访问时跳过内容数据传输,并且客户端支持条件GET。如果不能使用Last-Modified,则可以使用ETag作为替换(参见上面的讨论)。使用Last-Modified来允许HTTP/1.0兼容客户端的条件GET至关重要。

如果内容可能会稍有延迟,则应适当调整Expiresmax-ages-maxage [原文如此]。例如,如symcbean的答案所暗示的,为这些人添加5秒钟可能对高度流行的网站有很大帮助。请注意,与条件GET不同,增加到期时间将减少服务器负载,而不仅仅是减少服务器传出数据通信量(因为服务器总共会看到较少的请求)。

挥发性非公开内容

Date: <current time> 
Expires: <current time> 
Cache-Control: private, max-age=0, s-maxage=0 
Last-Modified: <real-last-modification-time> 
Vary: Cookie 

理由:告诉HTTP/1.0客户端和代理这种反应,应立即认为是过时的。包含Last-Modified时间以允许在资源再次访问时跳过内容数据传输,并且客户端支持条件GET。如果不能使用Last-Modified,则可以使用ETag作为替换(参见上面的讨论)。使用Last-Modified来允许HTTP/1.0兼容客户端的条件GET至关重要。还请注意,Cache-Control不得包含no-cache,must-revalidateno-store,因为使用这些指令中的任何一个都会打破至少一个用户代理中的后退按钮。但是,如果服务器传输的内容包含不应存储在永久存储器中的敏感内容,则必须使用no-store标志,而不管中断后退按钮。 警告:请注意,如果操作系统启用了交换并且交换未加密,则使用no-store无法防止敏感内容在硬盘上未经加密而结束! 另请注意,除非连接已加密(HTTPS/SSL),否则使用no-store意义不大。

2

晴OK,不过,你需要牢记的是HTTP 1.0的代理可以缓存内容提供/最多为

Cache-Control: private 

因此随着到期,你应该设定一个明确的日期修改的标头,以及承担头。

对于您的'静态非公开内容',您应该添加'Varies:Cookie'标头。

对于您的“易变的公共内容”:它变化的速度有多快?设置+5秒的TTL可能会减轻服务器的工作量。

对于'非易失性非公开内容',您应该添加no-cache,并且必须对Cache控制标题进行重新验证。

从服务器发出的Pragma头应该不会影响客户端或代理服务器。

做测试出你的时候缓存过期(IME,你可以结束了不止一个没有填充缓存访问由于所有条件要求更慢的系统/ 304响应)

+0

我知道'Cache-Control:private'不能被HTTP/1.0代理理解。这就是我把'Date'和'Expires'放到当前时间的原因。如果我理解正确,这应该立即从HTTP/1.0代理中过期。为什么我需要显式的'Date-Modified'头文件?某些用户代理是否需要它? –

+0

我认为在'非易失性非公开内容'中添加'no-cache,must-revalidate'将会打破至少Firefox和Internet Explorer的后退按钮。如果可能的话,我的意图是保持按钮显示实际的历史记录(而不是透明的服务器状态视图);有关详细信息,请参阅http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.13。 –

+0

我认为标题语法是'Vary:Cookie'。我曾考虑过这个问题,但是因为用户代理(浏览器)也承认这个头部会破坏用户代理缓存。例如:我在'http:// domain.com/icon/12'上有一个配置文件映像,它只为选定的已认证用户返回。我有一个会话ID为'5f2'的访问者X,我允许图像给那个用户。访客X注销,然后再次登录。现在X的会话ID为'2e8',存储在会话cookie中。如果我有'Vary:cookie',则X的用户代理不能使用缓存的图像。从技术上讲,'Vary:cookie'应该是正确的。 –