浏览器缓存¶
一般背景:为什么在浏览器中缓存是一个好事¶
在任何网站上,让浏览器缓存静态对象(即不包含用户内容,并且几小时、几天或几周都相同)都是一种好做法。
这通常意味着像.css、.js和图像文件这样的文件。
但某些内容变化非常快,所以不能被浏览器缓存。
如果浏览器被告知“不要缓存此对象”
那么它会知道不要。这就是网站(和Redmine)在可能更改的页面上所做的:例如,问题页面:它将在HTTP头中放入该消息。
但是,如果没有这样的说明 - 如果浏览器不确定它最近已经下载过的页面组件
它将向服务器发送一个304请求:表示“你能告诉我,这个文件是否仍然没有过时”。带有304的,服务器不需要再次发送整个对象:只需发送一个简短的“是的,它仍然新鲜”的回答。
在Redmine的默认设置中:它在每个页面上都会生成大量的304连接:您可以在Firebug等工具中看到这些。每个.css和.js文件等都有很多。
这对用户体验很不好:因为浏览器必须等待这些响应,然后才能继续构建页面。
因此,我们需要告诉浏览器这些对象不会长时间过时
有简单的方法可以配置Apache和nginx来做到这一点:通过告诉它们在HTTP头中设置“过期”日期,将其设置为未来很长时间:这样浏览器就知道:“好的,这个对象没有过时,因为我们还在过期日期之前”。
因此,当新用户访问Redmine时,他们的浏览器在第一页将获取.css和.js文件等,但在之后的页面上:不需要再次获取它们。
用户将体验到更快的网页构建速度!
Redmine的问题¶
不幸的是,Redmine(相当不明智地)使用.js文件名,用于包含用户内容的东西:即不应该在浏览器中缓存的东西。
这意味着;如果在Apache/nginx中添加一个简单的配置,来缓存所有名为*.js的东西:那么你的Redmine就会崩溃!
请参阅问题#17770 - 在那里报告了这个问题,看看Redmine团队是否可以将其更改为停止在错误的位置使用.js。
使用简单配置时,它会崩溃的地方有:(a) 在一期中编辑期刊时 (b) 在一期中上传文件时
Redmine的解决方案¶
简单情况,如上所述会破坏Redmine,因为它不关心js文件在哪个目录中:例如
location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ { expires 365d; }
因此需要使用更复杂的配置:在设置缓存标题之前,也会检查.js文件所在的目录。
我已经让这个工作起来了
# the regex logic: after either /javascripts/ or /stylesheets/ find the suffixes we want, followed by any quantity of numbers 0-9 # This works because the files we want to cache always appear after one of those 2 directories: but not the files we want to ignore # /journals/edit/24174.js and /uploads.js?attachment_id=1&filename=my-file-to-upload.png location ~* /(?:(?:plugin_assets|themes).+)?(javascripts|stylesheets|images|favicon).+(css|js|jpg|gif|ico|png)(\?[0-9]+)$ { # add_header X-SV-test 304-killer; use this do-nothing HTTP Header, if you need to play with the regexp #- for testing without fear of breaking anything! expires 365d; }
从redmine 3.4.0版本开始(#24617),静态文件请求会附加一个?timestamp,以避免在升级redmine版本时缓存服务错误文件的问题。然而,自定义主题不会附加时间戳到请求,因此application.css和responsive.css可能会异常崩溃。请参阅#29625以获取解决方案。
如果您想确保安全,请不要缓存没有?timestamp的文件
- # the regex logic: after either /javascripts/ or /stylesheets/ find the suffixes we want, followed by any quantity of numbers 0-9
+ # the regex logic: after either /javascripts/ or /stylesheets/ find the suffixes we want, followed by one or more numbers 0-9
# This works because the files we want to cache always appear after one of those 2 directories: but not the files we want to ignore
# /journals/edit/24174.js and /uploads.js?attachment_id=1&filename=my-file-to-upload.png
- location ~* /(?<file>/(?:(?:plugin_assets|themes).+)?(?:javascripts|stylesheets|images|favicon).+(?:css|js|jpe?g|gif|ico|png|html|woff|ttf|svg)(\?[0-9]+)?$) {
+ location ~* /(?<file>/(?:(?:plugin_assets|themes).+)?(?:javascripts|stylesheets|images|favicon).+(?:css|js|jpe?g|gif|ico|png|html|woff|ttf|svg)(\?[0-9]+)$) {
请注意,在nginx中:"expires"是设置对象"Expiry" HTTP头的配置。
在上面的例子中,365d表示365天。
有关nginx 'expires'配置的完整详细信息:https://nginxserver.cn/en/docs/http/ngx_http_headers_module.html#expires
对于Apache:请参阅mod_expires:https://httpd.apache.ac.cn/docs/2.2/mod/mod_expires.html