How to create a browser cache save URL to a javascript or css file in SharePoint

Often it is necessary to ensure that updates to files on the server get populated to the client asap. Especially when it comes to dependencies to custom javascript of CSS files and server controls.

SharePoint itself does this by adding a query string to some of its vital Javascript files. E.g.:

/_layouts/1033/core.js?rev=PQia%2B0EyudqxiQyTfOSR%2Fw%3D%3D

Whenever the core.js file changes on the server a new query string value is generated. That allows browsers to cache the file as long as the file does not change on the server.

Today I got the question if it is possible to utilize the same method for custom js and css files. The answer is yes.

SharePoint provides the functionality to generate browser cache save Urls for such files if they reside inside the _layouts directory or one of it’s localized subdirectory using the following method:

public static string Microsoft.SharePoint.Utilities.SPUtility.MakeBrowserCacheSafeLayoutsUrl(string name, bool localizable)

The first parameter needs to be the filename without a path (e.g. test.css) the second defines if the file resides in a language specific subdirectory or directly in the _layouts directory.

The following code will (e.g.) create the output below for german locale:

string saveUrl = Microsoft.SharePoint.Utilities.SPUtility.MakeBrowserCacheSafeLayoutsUrl("my-own.js", true);

/_layouts/1031/my-own.js?rev=PQia%2B0EyudqxiQyTfOSR%2Fw%3D%3D

7 Comments


  1. We had an issue for a major client related to HTTP content expiration of resources served from "_layouts", and I’d like to share my findings (so please correct me if I’m wrong). We decided not to use the API you’re referring to, because

    a) it works against the IIS infrastructure and common sense (there’s no reason to hash static binaries when the IIS infrastructure provides this for free and serves the right HTTP status codes).

    b) it leaves a lot of stale files in the users’ browser (change the original file on the server by mens of deployment, and the user will never make use of the file again).

    When SharePoint creates the "_layouts" virtual directory in IIS, it also configures HTTP content expiration with a value of 1 year (expressed in seconds). Effectively, this instructs the browser to hang on to the resource for a full year and never ever ask for changes to the original file.

    Unless the user actually initiates a forced reload (F5, CTRL+F5 or whatever), there’s no way users will receive your changes to any resources requested from the "_layouts" virtual directory. By default (and regardless of the expiration settings in most browsers), when a new instance of the browser is started, a full requests for all associated resources is initiated; the HTTP responses from the server might be mixed HTTP 200s (OK) or HTTP 302s (Not Modified).

    In general, using querystring params to flag a resource as changed is something you should really consider not doing; it’s much better to use HTTP headers. Also, if you opt for the HTTP content expiration route, make sure you use a more sensible value than a full year; odds are you’ll make changes to your "static" files in the mean time and want the browsers to reflect that.

    Anders Borum

    Software Architect, ProActive A/S

    Denmark

    Reply

  2. Hi Anders,

    an interesting discussion point!

    Lets jump on the browser behavior first: most browsers indeed behave or first request after a restart as if the content in the cache has expired. But this is not controlable by the server.

    Regarding the one year for content expiration and the query string values:

    The goal is to minimize network requests and especially the amount of data downloaded to the client.

    On the other hand it needs to be ensured that when you install a hotfix that replaces a control and with the control a javascript file that has specific code for this control are in sync.

    The server cannot control when the browser refreshes his cache.

    Hotfix install cycles also cannot be predicted by the product team in advance.

    So what could you do here to ensure that the control executed on the server and the javascript file loaded into the browser is always in sync?

    1) disable caching – not a good option with the large js files sent by sharepoint

    2) configure the expireation to the time when the content will change – that is more or less impossible as it is usually not predictable when content will change in the future.

    3) configure a small expiration value – e.g. 5 minutes – that causes lots of network traffic to check if the file has been changed or not. Overhead that should be avoided if possible. In case that no hotfix installed then it could take 1 year or longer for the file to get changed: when the next service pack is released and installed. But even then – if only a small number of files is replaced – there is a nearly 5 minute timeframe where errors can occur on the client side because the javascript file and the rendered content from the updated control is no longer in sync.

    4) use a query string – that has the benefit that you can ensure that the javascript file and the control are always in sync: changing the static file will cause a different query string to be generated. The only caveat I can see with this approach is that the browser cache gets filled with a different copy for each update.

    But how often will you change the files? I think the overhead in used disk space on the browser for regular update cycles is pretty low.

    Cheers,

    Stefan

    Reply

  3. Hi Gael,

    also an interesting approach! It is good if your performance killer is network latency. But not if it is network speed in general.

    The caveat with this approach: if the sum of all your JS files is 500 KB and you change a 10 KB js file then again all 500 KB have to be downloaded.

    Cheers,

    Stefan

    Reply

  4. To summarise the above, there’s not way for the server to tell the browser to use an updated file if the file a) uses the same name and b) is cached without changing the file name or using a technique like this. Changing the file name (eg. versioning it or datestamping it) could be disruptive and the querystring approach sounds like the next best option. Presumably the browser will delete cached files as its maximum cache threshold is reached so caching multiple files on the client shouldn’t be a major consideration.

    Reply

  5. Hi,

    Could you plz explain me where i have to add the code to clear the user’s browsers cache when i update the master CSS.

    I understood the concept but i am not sure how to implement this to work.

    machander.g@gmail.com

    Thanks in advance

    Reply

  6. Hi Machendra,

    there is no need to to this.

    Just ensure that the link to the CSS in your master page is generated though the above listed code line.

    Cheers,

    Stefan

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.