使缓存的脚本文件在客户端计算机上刷新

时间:2013-03-30 10:43:10

标签: asp.net caching iis-7 .net-4.0

我们在其中一个生产基地遇到了问题。 JavaScript文件已更新为页面并上载到IIS。我们直接使用

包含文件
<script src="PATH_TO_SCRIPT" type="text/javascript"></script>

我们开始收到客户抱怨页面被破坏的投诉。当JS文件缓存在客户端计算机上并且没有从服务器刷新时,就会发生这种情况。

如何在不改变javascript文件名的情况下避免这种情况?

ASP.Net捆绑和缩小可能会有所帮助。但是有很多页面和网站是相当遗留的。几乎所有页面都有一些在相关js文件中编写的重逻辑。

该网站正在运行.Net 4.0和IIS 7

2 个答案:

答案 0 :(得分:2)

捆绑和缩小确实是处理此问题的正确方法,因为它会在渲染脚本时正确地将正确的版本号附加到URL。

但是如果这是一个遗留站点并且由于某些原因你不能使用捆绑,一种可能性是编写一个服务器端助手,它将生成脚本标记并计算文件的校验和并附加正确的查询字符串参数:

public static class ScriptExtensions
{
    public static string Script(this Page page, string relativeUrl)
    {
        var path = page.Server.MapPath(relativeUrl);
        if (File.Exists(path))
        {
            return string.Format(
                "<script type=\"type/javascript\" src=\"{0}?v={1}\"></script>",
                page.ResolveUrl(relativeUrl),
                Hash(path)
            );
        }
        return string.Empty;
    }

    private static string Hash(string file)
    {
        using (var stream = File.OpenRead(file))
        using (var bs = new BufferedStream(stream))
        {
            using (var sha1 = new SHA1Managed())
            {
                byte[] hash = sha1.ComputeHash(bs);
                var result = new StringBuilder(2 * hash.Length);
                foreach (byte b in hash)
                {
                    result.AppendFormat("{0:X2}", b);
                }
                return result.ToString();
            }
        }
    }
}

然后在你的WebForm中使用帮助器来包含你的脚本:

<%= this.Script("~/scripts/example.js") %>

将发出以下标记:

<script type="type/javascript" src="/scripts/example.js?v=3C222D8DFA2A02A02E9A585EA6FE0D95673E8B4A"></script>

现在,当您更改脚本文件的内容时,其SHA1校验和将不同,并且将生成不同的版本查询字符串参数并附加破坏所有客户端缓存。

答案 1 :(得分:0)

受到Darin解决方案的启发,我决定选择Bundling and Minification来获得它所提供的所有好东西的好处,我提出了以下解决方案。使用页面类型的扩展方法添加静态类:

public static class ScriptExtensions
{
    public static string Script(this Page page, string relativeUrl)
    {
        var path = page.Server.MapPath(relativeUrl);
        if (File.Exists(path))
        {
            return BundlesConfig.AddPageScript(relativeUrl);
        }
        return string.Empty;
    }
}

BundlesConfig类包含为js文件生成包并添加到Bundles的方法:

public class BundlesConfig
{
    private static readonly ICollection<string> addedScripts 
                                                     = new HashSet<string>();
    private static readonly string bundleTemplate = "~/bundles/scripts/{0}";

    internal static string AddPageScript(string relativeUrl)
    {            
            var fileName = CleanFileName(relativeUrl);
            var bundleName = string.Format(bundleTemplate, fileName);

            if(!addedScripts.Contains(fileName))
            {
                var bundle = new ScriptBundle(bundleName);
                bundle.Include(relativeUrl);
                addedScripts.Add(fileName);
                BundleTable.Bundles.Add(bundle);
            }
      return System.Web.Optimization.Scripts.Render(bundleName).ToHtmlString();
    }

    private static string CleanFileName(string url)
    {
        if (url.Contains("/"))
        {
            return url.Substring(url.LastIndexOf("/") + 1).Replace('.', '_')
                          .Replace("-", "__");
        }

        return url.Replace('.', '_').Replace("-", "__");
    }
}

现在在页面上而不是标准script标记:

<scrip type="text/javascript" src="/scripts/jquery-min.js"></script>

我们使用:

<%= this.Script("~/Scripts/jquery-min.js") %>

该方法吐出以下内容:

<script type="text/javascript" src="/bundles/scripts/jquery__min_js?v=...."></script>