如果修改 – 因为与if-none-match
if-modified-since和if-none-match之间有什么区别? 我有一种感觉,如果无匹配用于文件,而if-modified-since用于页面?
关于Last-Modified/If-Modified-Since
和ETag/If-None-Match
之间的区别:
两者可以互换使用。 然而,取决于资源的types以及它在服务器上的生成方式,其中一个或另一个问题(“自从…之后已经修改了吗?”/“这是否仍然匹配这个ETag?”)可能更容易回答。
例子:
- 如果您正在提供文件,则使用该文件的
mtime
作为Last-Modified
date是最简单的解决scheme。 - 如果您正在提供一个由许多SQL查询构build的dynamic网页,那么检查这些查询返回的数据是否已经改变可能是不切实际的(除非所有这些查询都有某种“最后修改”列)。 在这种情况下,使用例如页面内容的md5散列作为
ETag
将会容易ETag
。
OTOH,这意味着您仍然需要在服务器上生成整个页面,即使是有条件的GET也是如此。 搞清楚ETag(主键,修订号等等)究竟是什么东西可以为你节省很多时间。
有关该主题的更多详情,请参阅以下链接:
If-Modified-Since
与Last-Modified
进行比较,而If-None-Match
与ETag
进行比较。 Modified-Since
和ETag
都可用于标识资源的特定变体。
但是If-Modified-Since
与Last-Modified
为您提供了caching的变体是旧的还是新的信息,而If-None-Match
与ETag
只是给出了信息是否相同 。 此外,大多数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-Since
和If-None-Match
。 - 如果之前已经呈现新的访问者,则不会重新呈现页面。
- 永远不要陈旧的内容。
注意事项:
- 如果我们要发送一个304,就不需要从memcached中获取呈现的html。所以你可以把它分别存储在memcached中,并且在etag中添加一个前缀作为关键字。
- 当你改变你的渲染代码的时候,api数据不会改变,但是你的渲染的html是可以的。 因此,您将只能看到caching的html,因此您将无法看到所做的更改。 为了避免这种情况,您需要在每次构build时生成一个随机的小string,并在散列之前将其附加到etags。
- 如果呈现的html不是api数据的纯函数(例如timeagostring),这将不起作用。 我们在WikiMentions上使用的解决方法是渲染gmt时间戳,并在React加载后将其转换为客户端上的timeago。
这可能不适用于所有人,具体取决于设置。 它适合我们。 我们使用龙卷风作为我们的api,而使用Node.js作为我们的前端。