I'm developing a web app in Dart, packaged in tomcat 6 as a deployable .war. This app is used by a bunch of clients, all with Google Chrome.
Every time I republish a new version, every single client must clear his browser cache before seeing the updated files: this is very annoying and I can't find any solution other than broadcast a mail to everyone "Please clear the browser cache".
The desirable solution is not a complete cache disable but that the browser keeps caching all stuff to be the quicker it could, and that I can control this at my wish.
I'm not sure what your question is about exactly.
There is nothing specific to Dart. Caching is handled by the browser depending on the expires headers the server returns with a response to a request.
What you can do is something like explained here Force browser to clear cache or Forcing cache expiration from a JavaScript file, and make the client application poll the server frequently for updates and then redirect to the new URL. You could implement some kind of redirection on the server or ignore the version URL query parameter, to be able to actually keep the same names of the resources.
Another possibility could be to use AppCache and serve the manifest file with immediate expiration. When you have an updated version modify the manifest file which makes the client reload the resources listed in the manifest (https://stackoverflow.com/a/13107058/217408, https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache, http://alistapart.com/article/application-cache-is-a-douchebag#section4).
Related
I am using webpack to bundle all of my files. Inside webpack I use chunkhash, Md5Hash and manifest to produce unique chunkhash for each of my files that get download by browser. It would look like this.
styles.3840duiel348fdjh385idfki.css
bundle.488503289dfksdlkor93lfui.js
vendor.sdkkfuuewkf892377rfkjdle.js
image.dkkdiiue9984ujjkfld003kfpp.png
This means that browser can cache them and if the hash is not changed it will use the cached version.At the same time I can for example just change styles and only that hash will be changed so when I deploy the app browser will download only the new styles.
The problem is that on my server i use this:
Cache-Control: public max-age=31536000
This represents aggressive caching and the browser will use cached version for one year unless URL, file name is changed. When I for example change styles my hash is changed and browser should request the new styles from server. That is according to this article(pattern 1) and a few more that I found https://jakearchibald.com/2016/caching-best-practices/
My problem is that when I update something, example styles, hash for styles is changed and I deploy that. The browser will not request new styles unles I hit reload while on my page. It will server the cached files. How can I fix this?
I can use Cache-Control: no-cache but that is not a solution because than browser has to check with server every time if he can use cached version. That is 4 http requests that are not needed every time someone visits the page.
The way I solved this is by adding one more number (which is Date.now()) into my file names as below.
filename: [name].${Date.now().valueOf()}.[chunkhash].js
This works pretty reliably for foreseeable time. The only drawback I see with this method is that: With each release, this forces all the bundles to be refreshed.
However, There are cases when chunkhash is rendered to create problem is when the modules do not change but their order changes (and hence the module id). The module id and order is not part of chunkhash! Please refer: https://github.com/webpack/webpack/issues/1856
Other alternatives is to use named module (which I believe will have some performance impact) besides may probably involve naming my modules which I am not sure of.
The browser is only instructed to load your assets when your page loads... That is just the way it works. You can poll or use any kind of push to the browser to detect backend changes and then force your users to refresh their browser.
This is not a caching issue, not a browser issue... just the fact that as soon as you have info it might already be outdated. You'll have to live with it or create a workaround.
See it as a calendar next to the coffee machine at your company which has an event 'party' this saturday. You see it and run to your coworkers to tell them the great news. Meanwhile the person who wrote the event on the calendar realized he has made a mistake and changes the event to next saturday. You don't have this new information so you will provide your coworkers with wrong information as long as you do not go for another coffee. The only way to know about the changes is if someone would notify you sooner than you go for another coffee... for example the person who wrote the event on the calendar sends an email to everyone to say sorry for his mistake and that the party is scheduled next saturday.
I did it like this. I use different webpack config for my client and server bundle. For my client bundle that has bundle.js, vendor.js, styles.css... I use chunkhash and Cache-Control: public max-age=31536000 as described in my question. For my server bundle that serves html(ejs) I use Cache-Control: no-cache. This works good because browser will contact server on every reload but that will be only one http request. If nothing is changed browser uses the cached version of all the assets since chunkhash in html didn't changed.
If for example I update styles and chunkhash is changed browser will see that when in contacts the server on reload and only new styles will be downloaded.
I am working on a trip planning application that used to implement offline support with the combination of appcache and localStorage. As soon as Service Worker became a viable option we started using it. Transition went without a hitch in Chrome (Chromium, Opera etc.) but Firefox (both 44 and 45) is posing some issues: Firefox registers new service worker but sill loads pages in its scope from the outdated appcache.
In other words, if you are lucky enough to never have stumbled upon our website, and if you open it for the first time in FF 44/45, you are going to get a new shiny service worker that takes care of all your offline needs. Life is great.
However if you had a misfortune to use Firefox before Service Worker was enabled you'd still have our website's older version in your appcache.
you go to the welcome page - the service worker gets activated and it (supposedly) takes care of handling everything for the entire scope
you log in, which redirects you one of the pages in SW scope (/ui) - it still should be handled by service worker, but instead Firefox suddenly realizes that it has that old appcache and without even trying to load anything from the network it loads the old content from the appcache
I would OK with that (alhough my reading of the Mozilla docs tells me that appcache should be ignored in the scope controlled by service worker) if that happened only once. Sadly Firefox does not even try to GET a manifest to check if that old appcache is up to date. If it did attempt to GET manifest, it would have received 404, which would invalidated the appcache (as it did on Chrome). I do not see anything like that on the wire (or on the server side).
To add insult to the injury Firefox console proudly anounces: The Application Cache API (AppCache) is deprecated and will be removed at a future date. Please consider using ServiceWorker for offline support. :-)
Simple refresh (F5) does load the current version of the page through the service worker. Sadly it only works once. After closing and reopening the tab the whole dance replays itself: service worker takes care of all the pages in the scope with the exception of the ones that used to have appcache manifest declaration.
Clearing the appcache (appcache clear in developer's console or through Settings UI) does remedy the situation, but I cannot possible suggest it to all our Firefox users.
I tried to find something Firefox bugzilla without much luck. If someone can find a relevant issue that would be great.
For now we just had to disable SW support for Firefox.
Is there any way of signaling to Firefox that it should ignore the old appcache when in Service Worker scope?
Why can't you just modify your appCache .manifest file? Provide an empty file, or garbage link, or some dummy page, just to get the new .manifest accepted, and the old one should be history.
I have a website which is displayed to visitors via a kiosk. People can interact with it. However, since the website is not locally hosted, and uses an internet connection - the page loads are slow.
I would like to implement some kind of lazy caching mechanism such that as and when people browse the pages - the pages and the resources referenced by the pages get cached, so that subsequent loads of the same page are instant.
I considered using HTML5 offline caching - but it requires me to specify all the resources in the manifest file, and this is not feasible for me, as the website is pretty large.
Is there any other way to implement this? Perhaps using HTTP caching headers? I would also need some way to invalidate the cache at some point to "push" the new changes to the browser...
The usual approach to handling problems like this is with HTTP caching headers, combined with smart construction of URLs for resources referenced by your pages.
The general idea is this: every resource loaded by your page (images, scripts, CSS files, etc.) should have a unique, versioned URL. For example, instead of loading /images/button.png, you'd load /images/button_v123.png and when you change that file its URL changes to /images/button_v124.png. Typically this is handled by URL rewriting over static file URLs, so that, for example, the web server knows that /images/button_v124.png should really load the /images/button.png file from the web server's file system. Creating the version numbers can be done by appending a build number, using a CRC of file contents, or many other ways.
Then you need to make sure that, wherever URLs are constructed in the parent page, they refer to the versioned URL. This obviously requires dynamic code used to construct all URLs, which can be accomplished either by adjusting the code used to generate your pages or by server-wide plugins which affect all text/html requests.
Then, you then set the Expires header for all resource requests (images, scripts, CSS files, etc.) to a date far in the future (e.g. 10 years from now). This effectively caches them forever. This means that all requests loaded by each of your pages will be always be fetched from cache; cache invalidation never happens, which is OK because when the underlying resource changes, the parent page will use a new URL to find it.
Finally, you need to figure out how you want to cache your "parent" pages. How you do this is a judgement call. You can use ETag/If-None-Match HTTP headers to check for a new version of the page every time, which will very quickly load the page from cache if the server reports that it hasn't changed. Or you can use Expires (and/or Max-Age) to reload the parent page from cache for a given period of time before checking the server.
If you want to do something even more sophisticated, you can always put a custom proxy server on the kiosk-- in that case you'd have total, centralized control over how caching is done.
I would like to create a rake task or something to clear the browser cache. The issue is, I am running a Flash app, and if I change the data, I more often than not need to reset the browser cache so it removes the old swf and can see the new xml data.
How do you reset the browser cache with ruby? Or even more precisely, how can I only remove a select item from the browser cache?
Thanks for the help!
I see a few possible solutions:
Write some shell script that deletes the temporary files from disk out the cache (what browser are you using?). I'm am not sure deleting the files on disk will necessarily work if the browser has them cached in memory.
Use and HTTP header (No-Cache) to avoid caching in the browser, Adobe has documentation on No-Cache. You could set this header only in development mode, so that in production the swf is cached.
Depending on your browser, force a page and cache refresh (e.g. Crtl-F5 in Firefox)
I'm not sure how you're loading the xml data, but in the past, I've gotten around the issue by appending a random number to the path of the xml file:
xml.load("data.xml?"+Math.random());
Basically, Flash will always think the file is a different URL. It won't be able to find a match in your cache.
Again, I'm not sure how you're loading the XML data, so I'm not sure if this applies to your situation.
Hope it helps, though.
You cannot reset browser cache, even if you would sometimes it will not be sufficient because caching can occur not only on the server and/or client, but also on any number of nodes your response goes through on its way from your server to your client.
The only tool at your disposal is the caching headers.
You can set them to NoCache just keep in mind that it will be hitting the server every time
Since you're using Safari, here's an article describing how to use AppleScript to clear the cache. But you can probably just skip the AppleScript part and remove the files directly in the rake task. The only catch might be that you have to restart the browser for it to take affect, but that could be done with a kill on the process and an "open /Applications/Safari.app" (I'm assuming you're on a Mac; in Windows it would be something like start "c:\program files\Safari...").
Is it possible to clear all site cache? I would like to do this when the user logs out or the session expires instead of instructing the browser not to cache on each request.
As far as I know, there is no way to instruct the browser to clear all the pages it has cached for your site. The only control that you, as a website author, have over caching of a page occurs when the browser tries to access that page. You can specify that cached versions of your pages should expire at a certain time using the Expires header, but even then the browser won't actually clear the page from its cache at that time.
i certainly hope not - that would give the web site destructive powers over the client machine!
If security is your main concern here, why not use HTTPS? Browsers don't cache content received via HTTPS (or cache it only in memory).
One tricky way to mimic this would be to include the session-id as a parameter when referencing any static piece of content on the site. When the user establishes the session, the browser will recognize all the pieces of content as new due to the inclusion of this parameter. For the duration of the session the browser will used the static content in its cache. After the user logs out and logs back in again, the session-id parameter for the static contents will be different, so the browser will recognize this is as completely new content and will download everything again.
That being said... this is a hack and I wouldn't recommend pursuing it.. For what reason do you want the user's cache to be cleared after their session expires? There's probably a better solution that can fit your situation as opposed to what you are currently asking for.
If you are talking about asp.net cache objects, you can use this:
For Each elem As DictionaryEntry In Cache
Cache.Remove(elem.Key)
Next
to remove items from the cache, but that may not be the full-extent of what you are trying to accomplish.