我正在使用webpack捆绑我的所有资产文件,所以我得到这样的东西.
bundle.7fb44c37b0db67437e35.js
vendor.495e9142a1f8334dcc8c.js
styles.bc5b7548c97362b683f5582818914909.css
我在名称中使用chunkhash,因此当浏览器缓存某些内容时,它会再次缓存,直到哈希值发生变化.例如,如果我在样式中更改某些内容,捆绑文件并进行部署,则只有样式的哈希值会发生变化,其他浏览器不会再次从服务器请求样式文件,其余的将从内存缓存中使用.
在响应标头中,我还有Etag和Last-Modified,每次我为每个文件部署应用程序时它们都会更改.我应该从响应中删除它们吗?这可能会混淆浏览器与服务器联系并查看文件是否已更改,即使哈希仍然相同?
最佳答案 好问题.这在很大程度上取决于后端的实现方式以及计算标头值的方式.这些文件是从我们的服务器提供的,还是像s3这样的其他东西?我们使用的是CDN吗?我们是否为我们的应用服务器使用框架?谁计算这些标题,Web服务器或应用程序服务器?
出于本答案的目的并且为了简单起见,我们假设我们使用的流行服务器框架Express没有CDN或第三方托管.与大多数应用程序服务器一样,Express根据所服务文件的内容计算ETag和Last-Modified,而不是文件名.
浏览器第一次请求我们的文件时,它将收到资源的ETag和Last-Modified.下次请求相同的资源时,浏览器会将缓存的ETag和Last-Modified标头发送到服务器.然后,服务器根据这些标头决定浏览器是否需要下载新版本的资源,或者缓存版本是否为最新版本.如果缓存的资源是最新的,则服务器将使用304 – Not Modified状态代码进行响应.状态代码是整个缓存系统的关键 – 它是浏览器决定是否应该使用缓存资源的方式.
为了生成ETag标头,Express将响应主体的二进制缓冲区表示传递给etag模块,该模块根据缓冲区(source: generating ETag header和source: generating hash)的内容计算SHA-1哈希.要生成Last-Modified标头,Express使用文件系统的上次修改时间(see lastModified
in docs).
当webpack构建一个新的bundle时,即使chunkhash是相同的,文件的二进制文件也会改变.这会导致Express输出不同的Etag和Last-Modified,这意味着下次请求资源时它不会响应304.如果没有304状态代码,浏览器将不必要地重新下载捆绑包.
回答
我认为这里最好的做法是禁用这些资产的ETag和Last-Modified标头,而是使用Expires或Cache-Control:max-age标头设置为远期(通常为1年)的日期.这样,如果捆绑包过期或者缓存中根本不存在,浏览器将仅重新下载捆绑包.