Unique URL for changed content

102 views
Skip to first unread message

Thomas Einwaller

unread,
Jul 30, 2013, 5:33:57 AM7/30/13
to wr...@googlegroups.com
As I stated in my last post I am having troubles with getting browsers to reload the JS and CSS files of my app after changes because of the aggressive caching headers wro4j creates. So I am thinking of creating unique URLs for loading them and it seems like I am not the only one, as these issues show:



So my question: Is somebody working on this currently our should I give it a try? 

I can not see how anybody can use wro4j currently in a production app without those unique URLs, am I missing something?

Julien Wajsberg

unread,
Jul 30, 2013, 5:41:18 AM7/30/13
to wr...@googlegroups.com
I may miss something here, but isn't the hash encoder naming strategy a good solution here ? (see http://code.google.com/p/wro4j/wiki/OutputNamingStrategy)
or maybe this only works for build-time ?

Alex Objelean

unread,
Jul 30, 2013, 5:49:49 AM7/30/13
to wr...@googlegroups.com
By default, WroFilter uses ETags, which are modified once the content is changed. As result, the client should always get the latest version of bundled resources.
It is possible to build aggressive cache URL for resources using wro4j-taglib or building the url in a custom way (using OutputNamingStrategy) which currently is being used only by wro4j-maven-plugin.

You can easily extend almost anything to make wro4j the way your application needs. This flexibility comes with a cost: probably default implementation is not perfect for your requirements. There are 
open issues, including those mentioned by you, which are in progress or awaiting to be fixed (contributions are welcome) which would help extending less painful. 

Cheers,
Alex

Thomas Einwaller

unread,
Jul 30, 2013, 5:57:32 AM7/30/13
to wr...@googlegroups.com
Thanks Julien, but this only works when using the maven plugin and I was looking for a solution that does not depend on this built time mechanism.

Thomas Einwaller

unread,
Jul 30, 2013, 6:01:17 AM7/30/13
to wr...@googlegroups.com
I am aware of the ETags but it seems they do not have the expected effect because if the browser does not ask the server if the resource has changed the ETag is useless.

Maybe this has something todo with my last post, referring to https://developers.google.com/speed/docs/best-practices/caching which states:

  • Expires and Cache-Control: max-age. These specify the “freshness lifetime” of a resource, that is, the time period during which the browser can use the cached resource without checking to see if a new version is available from the web server. They are "strong caching headers" that apply unconditionally; that is, once they're set and the resource is downloaded, the browser will not issue any GET requests for the resource until the expiry date or maximum age is reached.
So the browser is not making a request and takes the file from the local cache without checking if there is a new version. I will try to remove the Expires and Cache-Controll Header as you suggested in your last post and let you know.

I would also be glad to contribute a JSP tag that generates a unique URL based on the ETag of the group if we need to have that.

Alex Objelean

unread,
Jul 30, 2013, 6:02:21 AM7/30/13
to wr...@googlegroups.com
The wro4j-taglib uses OutputNamingStrategy for runtime solution. Also, it is possible to roll out your custom solution. Since you know the mapping to WroFilter, you can extend GroupExtractor with a custom implementation and use OutputNamingStrategy to generate the aggressive cache URL. This should be straightforward and wasn't implemented simply because the default implementation can't be perfect for all use-cases.

Alex


--
You received this message because you are subscribed to the Google Groups "wro4j" group.
To unsubscribe from this group and stop receiving emails from it, send an email to wro4j+un...@googlegroups.com.
To post to this group, send email to wr...@googlegroups.com.
Visit this group at http://groups.google.com/group/wro4j.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Alex Objelean

unread,
Jul 30, 2013, 6:05:39 AM7/30/13
to wr...@googlegroups.com
Indeed, the ETag works as expected as long as browser ask for it on each request. I assume this behavior may differ from one browser to another. If that is the case, you can customize the response header to not set the Expires and Cache-Control. 

A contribution for JSP tag would be awseome. I didn't have enough time for adding new features. Most of the times I'm focusing in fixing existing bugs. So, if you can contribute with JSP implementation, that would be great.

Cheers,
Alex


--

Julien Wajsberg

unread,
Jul 30, 2013, 6:11:11 AM7/30/13
to wr...@googlegroups.com
On 30 July 2013 12:05, Alex Objelean <alex.o...@gmail.com> wrote:
Indeed, the ETag works as expected as long as browser ask for it on each request. I assume this behavior may differ from one browser to another. If that is the case, you can customize the response header to not set the Expires and Cache-Control. 


If there is no Expires header, the browser uses an internal heuristic depending on the file type.
If you want to force the revalidation, you can use a Expires header that is in the past. (and I'm not so good with the Cache-Control header so I won't enter into details here, you can read http://blog.marek.sapota.org/article/2012/08/17/web-browsers-and-cache-revalidation.html or http://www.mnot.net/cache_docs/#CACHE-CONTROL for extensive information).

Alex Objelean

unread,
Jul 30, 2013, 6:15:56 AM7/30/13
to wr...@googlegroups.com
Thanks Julien for clarification. Those links are very useful.

Alex

Thomas Einwaller

unread,
Jul 30, 2013, 7:31:22 AM7/30/13
to wr...@googlegroups.com
Thanks Julien for those links! As stated in to first one:

There are a couple of possibilities:

  • Change the URL if the file changed, for example by including hash of the data in the file name. This way browsers will be forced to reload the resource for each new version. This works well for URLs that are not meant to be seen by the user directly such as CSS or JS files, but is not suitable for HTML files that may be bookmarked, etc. Side note: some web frameworks do this for you by default — Ruby on Rails would be one of them.

I guess the unique URL is the way I want to go - this way I can be sure it is handled correct by most browsers. 

Julien Wajsberg

unread,
Jul 30, 2013, 8:41:32 AM7/30/13
to wr...@googlegroups.com
I may state the obious here, but note that wro4j could just ignore any hash suffix appended to the file name; however, the http request must have the unique url (eg with the hash or the file timestamp).

Alex Objelean

unread,
Jul 30, 2013, 8:51:00 AM7/30/13
to wr...@googlegroups.com
The hash (suffix or prefix) is built by OutputNamingStrategy. The GroupExtractor interface is responsible for extracting the name of the group from the HttpRequest. The default implementation of GroupExtractor assume there is no hash. But you can extend it an use a different logic.

Alex

mateusz...@gmail.com

unread,
Jul 30, 2013, 8:53:25 AM7/30/13
to wr...@googlegroups.com
We also had that issue and we modified the code to use build time solution for production environment and for development and debugging use WroFilter solution.
This is not ideal maybe but we decided to do this because: Runtime Solution has another nasty disadvantage to us that we need to eagerly precompile after deployed all resources and for that we use a special code to iterate over all resources and enforce compilation. Ideally we want maven do to this once for PROD configuration.

My suggestion is to run WroFilter for DEVELOPMENT and Maven Build Time solution for PROD

The addition would be nice anyway. There have been suggestions to use RequestHandler for that that would generate hash tag for a WRO group, then some UrlComposer would create a full URL.

Mateusz

mateusz...@gmail.com

unread,
Jul 30, 2013, 8:53:54 AM7/30/13
to wr...@googlegroups.com

Alex Objelean

unread,
Jul 30, 2013, 8:58:23 AM7/30/13
to wr...@googlegroups.com
This is an interesting approach, but it is not suitable when the number of groups is very large and unpredictable (for instance groups are built dynamically based on device it is being accessed from or pages whose content and resources differ based on various criteria). Using WroFilter in deployment can work pretty well, assuming you are using cache busting URL. If you are worrying about precompilation, you could put a Varnish & CDN in front of your web application. The compilation overhead happens only for very first requested resource and shouldn't be a problem even for a very large application.

Alex
Reply all
Reply to author
Forward
0 new messages