如果修改 – 因为与if-none-match

if-modified-since和if-none-match之间有什么区别? 我有一种感觉,如果无匹配用于文件,而if-modified-since用于页面?

关于Last-Modified/If-Modified-SinceETag/If-None-Match之间的区别:

两者可以互换使用。 然而,取决于资源的types以及它在服务器上的生成方式,其中一个或另一个问题(“自从…之后已经修改了吗?”/“这是否仍然匹配这个ETag?”)可能更容易回答。

例子:

  • 如果您正在提供文件,则使用该文件的mtime作为Last-Modifieddate是最简单的解决scheme。
  • 如果您正在提供一个由许多SQL查询构build的dynamic网页,那么检查这些查询返回的数据是否已经改变可能是不切实际的(除非所有这些查询都有某种“最后修改”列)。 在这种情况下,使用例如页面内容的md5散列作为ETag将会容易ETag
    OTOH,这意味着您仍然需要在服务器上生成整个页面,即使是有条件的GET也是如此。 搞清楚ETag(主键,修订号等等)究竟是什么东西可以为你节省很多时间。

有关该主题的更多详情,请参阅以下链接:

If-Modified-SinceLast-Modified进行比较,而If-None-MatchETag进行比较。 Modified-SinceETag都可用于标识资源的特定变体。

但是If-Modified-SinceLast-Modified为您提供了caching的变体是旧的还是新的信息,If-None-MatchETag只是给出了信息是否相同 。 此外,大多数ETag生成器都包含系统特定索引节点的信息,因此将文件移动到其他驱动器也可能会更改ETag

Last-Modified / If-Modified-Since中使用的时间戳值的精度有限 – 一秒钟,这对快速更改内容是不够的,例如Web聊天应用程序,在任何给定的秒钟内都可以发送多个消息。 ETag / If-None-Match可以帮助解决这个问题。

正如谷歌最佳实践中所述:

为所有可caching资源指定Expires或Cache-Control max-age之一,以及Last-Modified或ETag之一。 指定Expires和Cache-Control:max-age,或指定Last-Modified和ETag都是多余的。

https://developers.google.com/speed/docs/best-practices/caching

If-Modified-Since使用date,而If-None-Match使用ETag 。 它们都可以用于“页面”(即HTML)和其他文件。

除非被服务器声明为弱,否则ETag被认为是一个强有力的validation器,因此可以用来满足条件范围的请求。 但是,大多数自动生成的ETags在服务器场中都会遇到困难,因为它们通常使用inode信息和/或唯一的持久性计数器。 在实践中,我发现Last Modified头文件对于相当静态的内容是足够的,例如提供受保护的静态内容,因为文件的写入时间是相当好的validation器。

ETag是迄今为止最灵活的。 符合要求的客户需要在有条件的请求中发送ETag,而如果可用的话,他们应该发送。

由于Google和Bing机器人都使用If-Modified-Since而不是If-None-Match ,所以最好支持它。

即使在复杂的页面上,也有一种方法可以支持If-Modified-Since ,而无需跟踪修改时间。 我们在WikiMentions.com上使用这个方法。 这种方法对设置做了很多假设。 它可能不适合每个人。

您呈现的html需要是由api调用返回的数据的纯函数。 考虑示例页面example.com/shows/cosmos 。 它可能需要多个API调用:

 api.example.com/shows/cosmos api.example.com/cast/cosmos api.example.com/related/cosmos api.example.com/featured 

如果每个调用都返回一个etag,那么你可以通过连接这些etag来生成一个etag,并对结果进行哈希运算。 然后你可以使用这个作为html页面的etag。 然后,您可以将这个etag存储在memcached中,以及它创build的时间和生成的html。

 { “Modified”: timestamp, “Content”: rendered page, “E-tag”: hash of concatenated etags of api calls } 

现在,当第一次请求页面时:

  • 使页面的API调用
  • 生成级联的etag
  • 在memcached中查找etag(它不会存在)
  • 渲染页面
  • 将它添加到memcached
  • 发送给用户

当某个其他新访问者再次请求页面时:

  • 使页面的API调用
  • 生成级联的etag
  • 在memcached中查找etag(它将存在)
  • 发送上次访问的caching副本

当返回的访问者请求页面时(使用If-Modified-Since):

  • 使页面的API调用
  • 生成级联的etag
  • 在memcached中查找etag(它将存在)
  • 如果memcached中的修改时间晚于If-Modified-Since
    • 发送caching副本
  • 其他
    • 发送一个304没有修改

优点:

  • 可以同时支持If-Modified-SinceIf-None-Match
  • 如果之前已经呈现新的访问者,则不会重新呈现页面。
  • 永远不要陈旧的内容。

注意事项:

  • 如果我们要发送一个304,就不需要从memcached中获取呈现的html。所以你可以把它分别存储在memcached中,并且在etag中添加一个前缀作为关键字。
  • 当你改变你的渲染代码的时候,api数据不会改变,但是你的渲染的html是可以的。 因此,您将只能看到caching的html,因此您将无法看到所做的更改。 为了避免这种情况,您需要在每次构build时生成一个随机的小string,并在散列之前将其附加到etags。
  • 如果呈现的html不是api数据的纯函数(例如timeagostring),这将不起作用。 我们在WikiMentions上使用的解决方法是渲染gmt时间戳,并在React加载后将其转换为客户端上的timeago。

这可能不适用于所有人,具体取决于设置。 它适合我们。 我们使用龙卷风作为我们的api,而使用Node.js作为我们的前端。