我看到的行为与提到该问题的 codeplex 链接中描述的行为相同:
即如果我按以下顺序访问这些 URL,则行为是 -
bundle.css?v=1234 : no-cache
bundle.css : public
bundle.css?v=1234 : public
我决定深入研究 System.Web.Optimization 源代码,看看发生了什么。在Bundle类上,有一个私有方法设置headers,貌似落入了这段代码中:
if (noCache) {
cachePolicy.SetCacheability(HttpCacheability.NoCache);
}
noCache 变量是通过参数设置的。本例调用方法为设置:
// Set to no-cache if the version requested does not match
bool noCache = false;
var request = context.HttpContext.Request;
if (request != null) {
string queryVersion = request.QueryString.Get(VersionQueryString);
if (queryVersion != null && bundleResponse.GetContentHashCode() != queryVersion) {
noCache = true;
}
}
长话短说,我们已经切换到使用 Azure CDN 作为我们的捆绑包,并根据程序集版本将版本查询字符串参数更改为 ?v=1.0.0.0(类似于 this question)。捆绑代码将“1.0.0.0”与捆绑内容的 SHA256 哈希码进行比较,结果将捆绑标记为无缓存。
我通过更新查询字符串以匹配内容哈希解决了这个问题。
不幸的是,GetContentHashCode 方法的访问级别被标记为内部,因此必须复制 implementation。我最终创建了一个从 Bundle 继承的类,以便它可以将版本号作为转换应用到 CdnPath:
public class ProxiedCdnBundle : Bundle
{
private readonly string _cdnHost;
public ProxiedCdnBundle(string virtualPath, string cdnHost = "")
: base(virtualPath)
{
_cdnHost = cdnHost;
}
public override BundleResponse ApplyTransforms(BundleContext context, string bundleContent, IEnumerable<BundleFile> bundleFiles)
{
var response = base.ApplyTransforms(context, bundleContent, bundleFiles);
if (context.BundleCollection.UseCdn && !String.IsNullOrWhiteSpace(_cdnHost))
{
string path = System.Web.VirtualPathUtility.ToAbsolute(context.BundleVirtualPath);
base.CdnPath = string.Format("{0}{1}?v={2}", _cdnHost, path, GetBundleHash(response));
}
return response;
}
private static string GetBundleHash(BundleResponse response)
{
using (var hashAlgorithm = CreateHashAlgorithm())
{
return HttpServerUtility.UrlTokenEncode(hashAlgorithm.ComputeHash(Encoding.Unicode.GetBytes(response.Content)));
}
}
private static SHA256 CreateHashAlgorithm()
{
if (CryptoConfig.AllowOnlyFipsAlgorithms)
{
return new SHA256CryptoServiceProvider();
}
return new SHA256Managed();
}
}