2012-11-16 83 views
0

是否MVC 4捆綁,解決問題與陳舊的.js文件?這些.js文件緩存在客戶端計算機上,因此它們有時不會使用新部署進行更新。陳舊的JavaScript緩存文件和MVC4

捆綁並讓框架算出etag是否可以解決MVC 4中的問題?

同樣,使用MVC 3時有什麼選擇?

回答

4

MVC 4捆綁發射捆綁的資源的哈希值。

例如,

<link href="@System.Web.Optimization.BundleTable. 
    Bundles.ResolveBundleUrl("~/Content/css")" 
    rel="stylesheet" 
    type="text/css" /> 

結果如下:

<link href="/Content/css?v=ji3nO1pdg6VLv3CVUWntxgZNf1z" 
    rel="stylesheet" type="text/css" /> 

應將該文件改變v參數也會發生變化,迫使客戶端重新下載該資源。

來源:http://bit.ly/xT8ZM5

1

您可以在MVC 3中使用它。它在System.Web.Optimization.dll之下。你可以下載並使用。

欲瞭解更多信息:http://nuget.org/packages/microsoft.web.optimization

例如在Global.asax的,補充一點:

bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
        "~/Scripts/jquery-{version}.js")); 

bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
        "~/Scripts/jquery-ui-{version}.js")); 

bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
        "~/Scripts/jquery.unobtrusive*", 
        "~/Scripts/jquery.validate*")); 

bundles.Add(new ScriptBundle("~/bundles/customjs").Include(
        "~/Scripts/jquery.custom.js")); 
// or what you want to add different js files. 
+0

它真的能解決客戶端沒有得到最新的.js即使該文件在服務器上的問題是改變了嗎?謝謝! – Alwyn

1

我最近所面對的腳本緩存問題。新的瀏覽器(尤其是Chrome)是緩存腳本,有時它們不會向服務器發送請求以檢查是否有新版本。

在MVC3應用程序中,我決定使用自定義路由處理程序來處理它。在html中,我將修訂追加到每個腳本鏈接。然後在我的處理程序中,我從url中取出修訂號,然後在服務器上搜索實際文件(例如,Path/Script.rev1000.js指向Path/Script.js)。

這裏是我的代碼:

public class ContentRouteHandler : IRouteHandler 
{ 
    private OzirRouteProvider _routeProvider; 

    public ContentRouteHandler(OzirRouteProvider routeProvider) 
    { 
     this._routeProvider = routeProvider; 
    } 

    public IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     return new ContentHttpHandler(this._routeProvider, this, requestContext); 
    } 
} 

internal class ContentHttpHandler : IHttpHandler, IRequiresSessionState 
{ 
    private OzirRouteProvider _routeProvider; 
    private ContentRouteHandler _routeHandler; 
    private RequestContext _requestContext; 

    public bool IsReusable { get { return false; } } 

    public ContentHttpHandler(OzirRouteProvider routeProvider, ContentRouteHandler routeHandler, RequestContext requestContext) 
    { 
     this._routeProvider = routeProvider; 
     this._routeHandler = routeHandler; 
     this._requestContext = requestContext; 
    } 

    public void ProcessRequest(HttpContext context) 
    { 
     string contentPath = context.Request.PhysicalPath; 
     string fileName = Path.GetFileNameWithoutExtension(contentPath); 
     string extension = Path.GetExtension(contentPath); 
     string path = Path.GetDirectoryName(contentPath); 

     bool minify = false; 

     // Here i get fileName like Script.rev1000.min.js 
     // I strip revision and .min from it so I'll have Script.js 
     var match = Regex.Match(fileName, "(\\.rev\\d+)?(\\.min)?$"); 
     if (match.Groups[2].Success) 
     { 
      minify = true; 
      fileName = fileName.Remove(match.Groups[2].Index, match.Groups[2].Length); 
      contentPath = Path.Combine(path, fileName + extension); 
     } 
     if (match.Groups[1].Success) 
     { 
      fileName = fileName.Remove(match.Groups[1].Index, match.Groups[1].Length); 
      contentPath = Path.Combine(path, fileName + extension); 
     } 

     if (!File.Exists(contentPath)) // 404 
     { 
      throw new HttpException(404, "Not found"); 
     } 

     DateTime lastModified = this.GetModificationDate(contentPath); 
     string eTag = this.GetETag(context.Request.RawUrl, contentPath, lastModified); 

     // Check for modification 
     string requestETag = context.Request.Headers["If-None-Match"]; 
     string requestLastModified = context.Request.Headers["If-Modified-Since"]; 
     DateTime? requestLastModifiedDate = requestLastModified == null ? null : (DateTime?)DateTime.Parse(requestLastModified).ToUniversalTime().TruncMiliseconds(); 

     // Compare e-tag and modification date 
     if ((requestLastModified != null || requestETag != null) && 
      (requestLastModified == null || requestLastModifiedDate == lastModified) && 
      (requestETag == null || requestETag == eTag)) 
     { 
      context.Response.StatusCode = 304; 
      context.Response.SuppressContent = true; 
      context.Response.Flush(); 
      return; 
     } 

     switch (extension) 
     { 
      case ".js": 
       context.Response.ContentType = "application/x-javascript"; 
       if (minify) // minify file? 
       { 
        string minContentPath = Path.Combine(path, fileName + ".min" + extension); 
        this.MinifyJs(contentPath, minContentPath); 
        contentPath = minContentPath; 
       } 
       break; 
      default: 
       throw new NotSupportedException(string.Format("Extension {0} is not supported yet", extension)); 
     } 

     // g-zip and deflate support 
     string acceptEncoding = context.Request.Headers["Accept-Encoding"]; 
     if (!string.IsNullOrEmpty(acceptEncoding) && acceptEncoding.Contains("gzip")) 
     { 
      context.Response.Filter = new System.IO.Compression.GZipStream(context.Response.Filter, System.IO.Compression.CompressionMode.Compress); 
      context.Response.AppendHeader("Content-Encoding", "gzip"); 
     } 
     else if (!string.IsNullOrEmpty(acceptEncoding) && acceptEncoding.Contains("deflate")) 
     { 
      context.Response.Filter = new System.IO.Compression.DeflateStream(context.Response.Filter, System.IO.Compression.CompressionMode.Compress); 
      context.Response.AppendHeader("Content-Encoding", "deflate"); 
     } 

     context.Response.AddCacheDependency(new CacheDependency(contentPath)); 
     context.Response.AddFileDependency(contentPath); 
     context.Response.Cache.SetCacheability(HttpCacheability.ServerAndPrivate); 
     context.Response.Cache.SetETag(eTag); 
     context.Response.Cache.SetExpires(DateTime.Now.AddDays(7)); 
     context.Response.Cache.SetLastModified(lastModified); 
     context.Response.Cache.SetMaxAge(TimeSpan.FromDays(7)); 

     context.Response.TransmitFile(contentPath); 
     context.Response.Flush(); 
    } 

    private void MinifyJs(string contentPath, string minContentPath) 
    { 
     this._log.DebugFormat("Minifying JS {0} into {1}", contentPath, minContentPath); 
     if (!File.Exists(minContentPath) || File.GetLastWriteTime(contentPath) > File.GetLastWriteTime(minContentPath)) 
     { 
      string content = File.ReadAllText(contentPath, Encoding.UTF8); 

      JavaScriptCompressor compressor = new JavaScriptCompressor(); 
      compressor.Encoding = Encoding.UTF8; 
      compressor.ErrorReporter = new CustomErrorReporter(LoggingType.Debug); 

      content = compressor.Compress(content); 

      File.WriteAllText(minContentPath, content, Encoding.UTF8); 
     } 
    } 

    private DateTime GetModificationDate(string contentPath) 
    { 
     DateTime lastModified = File.GetLastWriteTimeUtc(contentPath).TruncMiliseconds(); 

     return lastModified; 
    } 

    private string GetETag(string url, string contentPath, DateTime lastModified) 
    { 
     string eTag = string.Format("url={0},path={1},lm={2},rev={3}", url, contentPath, lastModified, AppInfo.Revision); 

     return Quote(GetHash(eTag)); 
    } 

    private static string GetHash(string value) 
    { 
     byte[] data = MD5.Create().ComputeHash(Encoding.UTF8.GetBytes(value)); 

     StringBuilder hex = new StringBuilder(data.Length * 2); 
     foreach (byte b in data) 
     { 
      hex.AppendFormat("{0:x2}", b); 
     } 
     return hex.ToString(); 
    } 

    private static string Quote(string value) 
    { 
     return string.Format("\"{0}\"", value); 
    } 
} 

要使用它,你必須打開RouteExistingFiles並註冊的路線,例如:

routes.Add(new Route("Content/{*resource}", new RouteValueDictionary(), new RouteValueDictionary { { "resource", @".*(\.css)$" } }, contentHandler)); 
routes.Add(new Route("Scripts/{*resource}", new RouteValueDictionary(), new RouteValueDictionary { { "resource", @".*(\.js)$" } }, contentHandler));