I would like to ask if there is a way to prevent Firefox from caching scripts (.js files).
I have a project (ASP.Net Web App) with caching issue on firefox. When I first
1) Install IIS module: http://www.iis.net/download/urlrewrite
2) Put this in web.config into section:
<rewrite>
<rules>
<rule name="Style Rewrite" stopProcessing="true">
<match url="^v(.*?)/styles/(.*)" />
<action type="Rewrite" url="/styles/{R:2}" />
</rule>
<rule name="Javascript Rewrite" stopProcessing="true">
<match url="^v(.*?)/javascript/(.*)" />
<action type="Rewrite" url="/javascript/{R:2}" />
</rule>
</rules>
</rewrite>
3) Write this helper function (into some global class)
public static string PutCSS(string filepath)
{
FileInfo f = new FileInfo(HttpContext.Current.Server.MapPath(filepath));
string timestamp = f.LastWriteTimeUtc.Year.ToString() + f.LastWriteTimeUtc.Month.ToString() + f.LastWriteTimeUtc.Day.ToString() + f.LastWriteTimeUtc.Hour.ToString() + f.LastWriteTimeUtc.Minute.ToString() + f.LastWriteTimeUtc.Second.ToString() + f.LastWriteTimeUtc.Millisecond.ToString();
return "<link type=\"text/css\" rel=\"stylesheet\" href=\"v" + timestamp + "/" + filepath + "\" />\n";
}
public static string PutJS(string filepath)
{
FileInfo f = new FileInfo(HttpContext.Current.Server.MapPath(filepath));
string timestamp = f.LastWriteTimeUtc.Year.ToString() + f.LastWriteTimeUtc.Month.ToString() + f.LastWriteTimeUtc.Day.ToString() + f.LastWriteTimeUtc.Hour.ToString() + f.LastWriteTimeUtc.Minute.ToString() + f.LastWriteTimeUtc.Second.ToString() + f.LastWriteTimeUtc.Millisecond.ToString();
return "<script type=\"text/javascript\" src=\"v" + timestamp + "/" + filepath + "\" ></script>\n";
}
4) Instead of:
<link href="Styles/style.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="Javascript/userscript.js" ></script>
Use:
<%= global.PutCSS("Styles/style.css")%>
<%= global.PutCSS("Javascript/userscript.css")%>
<head runat="server">
<%= "<link href='/asset/Style.css?v" + new Random().Next(1000,9999).ToString() + "' rel='stylesheet' />" %>
</head>
If you have control over the IIS configuration then you can put all your scripts inside one folder and tell IIS to expire the content immediately, or add other custom headers of your choice.
The appropriate page for IIS 6.0 is http://technet.microsoft.com/en-us/library/cc732442.aspx
I WANT the scripts and the styles to be cached... only reload them when they change... It is easy using the date of the file:
<script type="text/javascript" src="~/js/custom.js?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/js/custom.js")).ToString(),"[^0-9]", ""))"></script>
<link rel="stylesheet" href="~/css/custom.css?d=@(System.Text.RegularExpressions.Regex.Replace(File.GetLastWriteTime(Server.MapPath("~/css/custom.css")).ToString(),"[^0-9]", ""))" />
One technique is to add a random element to the URL as a querystring, so the browser doesn't know how to cache the script:
<script src="jquery.js?<%=DateTime.Now.Ticks %>" />
Even better would be to append the current build number of your assembly, so you get the performance benefits of script caching while the script hasn't changed. This only works however, if you never change your script files "out of band" with your binary releases.
You should be able to use
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
but you will have to have a http handler that renders the script directly to the response stream and than set the source url of the script tag to the handler or configure IIS to handle all javascripts using a specific handler: Point *.js to the aspnet_isapi.dll ISAPI Extension and than add the following in your web.config
<system.web>
<httpHandlers>
<!-- javascript handler -->
<add verb="*" path="*.js"
type="skmHttpHandlers.JavascriptHandler, skmHttpHandlers" />
</httpHandlers>
And than the handler:
namespace skmHttpHandlers
{
public class JavascriptHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.Clear();
context.Response.Cache.SetCacheability(HttpCacheability.NoCache)
using (var scriptStream = File.Open(Server.MapPath("~/script/TheScript.js"), FileMode.Open))
scriptStream.CopyTo(context.Response.OutputStream);
context.Response.End();
}
public bool IsReusable
{
get
{
return false;
}
}
}
}