BrowserCaching » History » Version 4
dj jones, 2014-09-01 15:38
| 1 | 1 | dj jones | h1. BrowserCaching |
|---|---|---|---|
| 2 | |||
| 3 | 2 | dj jones | h2. General Background: as to why caching in browser is a good thing |
| 4 | 1 | dj jones | |
| 5 | It is good practise on any website to let the browser cache objects that are static - ie don't contain user content, and are the same for hours, days or weeks. |
||
| 6 | |||
| 7 | (This in general means files like: .css, .js and image files) |
||
| 8 | |||
| 9 | But some content does change very fast, so must not be cached by the browser. |
||
| 10 | |||
| 11 | *If the browser is told 'don't cache this object':* |
||
| 12 | 4 | dj jones | then it knows not to. This is what Websites (and Redmine) do on the pages that may change: eg an issue page: it will put into the HTTP header that message. |
| 13 | 1 | dj jones | |
| 14 | *But in the absence of that - if the browser is not sure about a page component* |
||
| 15 | 4 | dj jones | that it already has recently downloaded, it will send a 304 request to the server: saying 'can you tell me, is this file still not stale'. And with a 304 the server does not need to send the whole object again: just a short 'yes, that is still fresh' answer. |
| 16 | 1 | dj jones | |
| 17 | 4 | dj jones | In Redmine's default set-up: it generates a lot of 304 connects on every page: you can see these in a tool like Firebug. One for every css and .js file etc. Many. |
| 18 | 1 | dj jones | |
| 19 | 4 | dj jones | These are bad for the user experience: because the browser has to wait for these responses, before it can carry on and build the page. |
| 20 | 1 | dj jones | |
| 21 | *So we need to tell the browser that these objects will not be stale for a long time* |
||
| 22 | |||
| 23 | There are easy ways to configure Apache and nginx to do this: by telling them to set the 'Expiry' date in the HTTP Header well into the future: so that the browser knows: OK, this objects is not stale, because we are still before the expiry date'. |
||
| 24 | |||
| 25 | 4 | dj jones | Thus when a new user visits Redmine, their browser on the first page will GET the .css and .js files etc, but on pages after that: does not need to get them again. |
| 26 | 1 | dj jones | |
| 27 | The users experience faster web page builds! |
||
| 28 | |||
| 29 | h2. The Problem with Redmine |
||
| 30 | Unfortunately, RedMine also uses .js file names, for things that DO content user content: ie things that should NOT be cached in the browser. |
||
| 31 | |||
| 32 | So this means; if in Apache/nginx you add a simple config, to cache anyting that is named *.js: then your Redmine will break! |
||
| 33 | |||
| 34 | 3 | dj jones | See the Issue #17770 - where this problem is reported, to see if the RedMine team can change RRedmine, to STOP using the .js in bad places. |
| 35 | 1 | dj jones | |
| 36 | Tne places it breaks if you use a simple config are: (a) when editing a journal in an issue (b) when uploading a file to an issue |
||
| 37 | |||
| 38 | h2.The work round for RedMine |
||
| 39 | 3 | dj jones | |
| 40 | 4 | dj jones | Is to use a more complex configuration: that also checks which directory the .js file is in, before setting the cache heading. |
| 41 | 1 | dj jones | |
| 42 | Etienne suggested this nginx configuration (see Issues #13564): |
||
| 43 | |||
| 44 | <pre> |
||
| 45 | location ~* ^(?:(?:plugin_assets/|themes/).+/)(?:javascripts|stylesheets|images)/.+\.(?:css|js|jpe?g|gif|htc|ico|png|html)$ { |
||
| 46 | 4 | dj jones | expires 365d; |
| 47 | } |
||
| 48 | 1 | dj jones | </pre> |
| 49 | |||
| 50 | The simple case, that will break Redmine, does not care about which directory eg: |
||
| 51 | <pre> |
||
| 52 | location ~* \.(ico|css|js|gif|jp?g|png)(\?[0-9]+)?$ { |
||
| 53 | expires 365d; |
||
| 54 | } |
||
| 55 | </pre> |
||
| 56 | 4 | dj jones | |
| 57 | Note that in nginx: 'expires' is the config that sets the 'Expiry' HTTP header in the object. |
||
| 58 | |||
| 59 | In the above, 365d means 365 days. |
||
| 60 | |||
| 61 | See nginx page: http://nginx.org/en/docs/http/ngx_http_headers_module.html#expires |