首页 文章

HTTP标头:控制缓存和历史记录机制

提问于
浏览
12

我希望能够提出不依赖于用户代理/协议版本嗅探的 Headers ,但如果没有别的话,我会接受 . 所有URL都是通过完全自定义处理程序获取的,因此我可以根据需要选择所有标头,这完全是关于中间代理和用户代理 . 如果可能,这应该与HTTP / 1.0和HTTP / 1.1客户端兼容 . 如果存在多个解决方案,则最好的解决方案将是通过线路发送的最短解决方案 .

Static public content

所有"Static public content"都是HTTP真正关注的东西:如果URL相同,则内容是相同的 . 我可以轻松地执行此操作:例如,我将用户配置文件图标放入http://domain.com/profiles/xyz/icon/1234abcd,其中"1234abcd"是图标文件内容的SHA-1 . 如果我将来改为图标,我现在正在思考一些问题:

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

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

Static non-public content

所有“静态非公开内容”都是静态的,但并非每个人都可以使用 . 实际上,此内容仅对选定的登录用户可用(会话保持会话cookie保持会话UUID) . 如果URL相同,则内容相同 . 但是,回应不公开 . 用例可以是在社交网络服务中与所选朋友共享的图像 . 我正在考虑一些事情:

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

这是否足以允许用户代理缓存并禁用代理?我需要 Pragma 吗?

Volatile public content

所有"Volatile public content"都是易变的东西,可供所有人使用 . 未登录时的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-ModifiedPragma 吗?

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

Volatile non-public content

所有"Volatile non-public content"都是易变的东西,并不是每个人都可以使用(私人) . 您登录时会出现http://slashdot.org/的首页 . 目的是允许在不变的URL中快速更新内容 . 请注意,我不想破坏用户代理历史记录机制(即,从易失性页面单击某些内容然后点击后退按钮不应导致从服务器获取易失性页面 - 但是,单击指向该服务器的链接首页应该从服务器获取资源) . 我正在考虑一些事情:

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

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


仍需要使用我建议的 Headers 进行测试的事情:

  • 验证私有内容不会通过HTTP / 1.0代理泄露 .

  • 验证缓存在代理中是否正常工作 .

  • 验证缓存在用户代理中是否正常工作 .

  • 验证用户代理历史记录机制是否适用于用户代理(所有情况) .

  • 确认遵循指向易失性页面的链接从服务器获取新鲜内容 .

  • 使用HTTPS而不是HTTP验证所有结果 .

2 回答

  • 2

    我会回答我自己的问题:

    Static public content

    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 Headers ,它应该反映真实数据而不是发明的东西 . 如果您想减少服务器数据传输(如果用户点击重新加载/刷新按钮)并且不能包含真正的 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 将无助于服务器加载,仅用于服务器传出的Internet管道/数据传输速率 .

    Static non-public content

    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 是因为支持 Cache-Control 的所有代理可能不支持 privatehttp://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3 - 我不知道哪些代理被破坏) . max-age 设置为 60*60*24*365 (1年)的值,因为HTTP / 1.1规范没有定义此参数的任何上限,我猜这是依赖于实现的 . Expires Headers 应该限制在未来一年,所以在这里使用相同的逻辑应该没问题 . 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)始终强制对包含 Vary: Cookie (源:http://blogs.msdn.com/b/ie/archive/2010/07/14/caching-improvements-in-internet-explorer-9.aspx)的资源进行条件GET . 这是因为MSIE的内部缓存实现不记得它第一次发送哪个Cookie,因此无法知道当前Cookie是否是同一个Cookie .

    但是,这是一个问题的示例,该问题是由于删除 Vary: Cookie 标头以显示为什么这确实是技术上正确的行为所必需的 . 请参阅上面的示例,并假设在X注销后,访问者Y使用相同的用户代理登录(用户代理可能已在X和Y之间重新启动,这无关紧要) . 如果Y查看包含指向 http://domain.com/icon/12 的链接的页面,那么Y会看到页面中嵌入的图标,即使Y不会认为这是一个足够大的问题,因为Y可以通过检查用户代理缓存来手动访问图标可能添加 Vary: Cookie . 但是,这个问题可能会阻止Y注意到他在技术上不会访问此内容(这可能很重要,例如,如果Y共同创作内容) . 如果内容被视为敏感内容,则无论此 Cache-Control 指令引起的问题如何,服务器都必须发送 no-store .

    在这里,添加 Last-Modified Headers 将有助于用户点击重新加载/刷新按钮(参见上面的讨论) .

    Volatile public content

    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,增加到期时间将减少服务器负载,而不是仅减少服务器传出数据流量(因为服务器总共会看到更少的请求) .

    Volatile non-public content

    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-cachemust-revalidateno-store ,因为使用这些指令中的任何一个都会破坏至少一个用户代理中的后退按钮 . 但是,如果服务器正在传输的内容包含不应存储在永久存储器中的敏感材料,则无论是否断开后退按钮,都必须使用 no-store 标志 . 警告:请注意,如果操作系统已启用交换且交换未加密,则使用 no-store 无法阻止敏感材料在没有加密的情况下在硬盘上结束! Also note that using no-store makes very little sense unless the connection is encrypted (HTTPS/SSL).

  • 10

    大多数情况下都可以,但是你需要记住,HTTP / 1.0代理可以缓存提供的内容

    Cache-Control: private
    

    因此,您应该设置明确的Date修改标头以及expires标头 .

    对于“静态非公开内容”,您应添加“Varies:Cookie” Headers .

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

    对于“易失性非公共内容”,您可能应该向Cache-control标头添加no-cache,must-revalidate .

    从服务器发出的Pragma头应该对客户端或代理没有影响 .

    测试缓存过期时会发生什么(IME你最终得到的系统比没有填充缓存的系统更慢,因为所有的条件请求/ 304响应)

相关问题