2015-07-05 3 views
0

В настоящее время я добавляю версию приложения ко всем JavaScript & Файлы StyleSheet для предотвращения кэширования в старых браузерах. Он работает нормально. Тем не менее, я хотел бы кэшировать все JavaScript & StyleSheet без какого-либо запроса на веб-сервер.Как заставить браузер кэшировать файл в IIS?

enter image description here

С текущей настройки, веб-сервер ответов, как на следующем рисунке. Я не хочу, чтобы браузер тратил время на проверку ETag для всех файлов стиля StyleSheet JavaScript &.

enter image description here

Вот текущая настройка в web.config

<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00" /> 
+1

Вы не можете * сила * браузер делать что-либо. – Richard

ответ

0

Как служит IIS файлы и отслеживает изменения, IIS всегда будет посылать заголовок кэша повторно проверки, заставляя браузер для проверки изменений. Чтобы избавиться от этой проблемы, мы разработали CachedRoute, как показано ниже, однако это хорошо работает в ASP.NET MVC, но с небольшими изменениями вы также можете реализовать их в ASP.NET WebForms.

Этот код также дает вам преимущество перемещения ваших статических ресурсов в CDN.

Cached Версия Префикс URL

Мы должны были придумать версии статического контента, как /cached/version/, это не что иное, как только префикс URL для статического актива. version может быть любой случайной буквенно-цифровой строкой, абсолютно бесполезной, но определяет другую версию.

Ну, один из самых простых способов - использовать ключ версии в URL-адресе.

Во-первых, создать версию сборки в AssemblyInfo.cs

[assembly: AssemblyVersion("1.5.*.*")] 

Оставить * в качестве замены номер сборки, .net компилятор автоматически инкремент с каждым билдом.

Или определить версию в настройках приложения, как следовать

<appSettings> 
    <add key="Static-Content-Version" value="1.5.445.55565"/> 
    <add key="CDNHost" value="cdn1111.cloudfront.net"/> 
</appSettings> 

// Route configuration 

// set CDN if you have 
string cdnHost = WebConfigrationManager.AppSettings["CDNHost"]; 
if(!string.IsEmpty(cdnHost)){ 
    CachedRoute.CDNHost = cdnHost; 
} 

// get assembly build information 
string version = typeof(RouteConfig).Assembly.GetName().Version.ToString(); 

CachedRoute.CORSOrigins = "*"; 
CachedRoute.Register(routes, TimeSpam.FromDays(30), version); 

Теперь на каждой странице, ссылки на статический контент как,

<script src="@CachedRoute.CachedUrl("/scripts/jquery-1.11.1.js")"></script> 

Оказывая, ваша страница будет оказана в виде (без CDN)

<script src="/cached/1.5.445.55565/scripts/jquery-1.11.1.js"></script> 

с CDN, как

<script 
     src="//cdn111.cloudfront.net/cached/1.5.445.55565/scripts/jquery-1.11.1.js"> 
</script> 

Ввод версии в URL-путь вместо строки запроса делает CDN лучше, поскольку строки запроса могут игнорироваться в конфигурации CDN (обычно это случай по умолчанию).

Преимущества Если вы установили версию такой же, как и с монтажной версией, легко установить новую сборку. В противном случае вы должны вручную изменить web.config при каждом изменении версии.

CachedRoute Класс от https://github.com/neurospeech/atoms-mvc.net/blob/master/src/Mvc/CachedRoute.cs

public class CachedRoute : HttpTaskAsyncHandler, IRouteHandler 
{ 

    private CachedRoute() 
    { 
     // only one per app.. 

    } 

    private string Prefix { get; set; } 

    public static string Version { get; private set; } 

    private TimeSpan MaxAge { get; set; } 

    public static string CORSOrigins { get; set; } 
    //private static CachedRoute Instance; 

    public static void Register(
     RouteCollection routes, 
     TimeSpan? maxAge = null, 
     string version = null) 
    { 
     CachedRoute sc = new CachedRoute(); 
     sc.MaxAge = maxAge == null ? TimeSpan.FromDays(30) : maxAge.Value; 

     if (string.IsNullOrWhiteSpace(version)) 
     { 
      version = WebConfigurationManager.AppSettings["Static-Content-Version"]; 
      if (string.IsNullOrWhiteSpace(version)) 
      { 
       version = Assembly.GetCallingAssembly().GetName().Version.ToString(); 
      } 
     } 

     Version = version; 

     var route = new Route("cached/{version}/{*name}", sc); 
     route.Defaults = new RouteValueDictionary(); 
     route.Defaults["version"] = "1"; 
     routes.Add(route); 
    } 

    public override bool IsReusable 
    { 
     get 
     { 
      return true; 
     } 
    } 

    public static string CDNHost { get; set; } 

    public static HtmlString CachedUrl(string p) 
    { 
     if (!p.StartsWith("/")) 
      throw new InvalidOperationException("Please provide full path starting with /"); 
     string cdnPrefix = string.IsNullOrWhiteSpace(CDNHost) ? "" : ("//" + CDNHost); 
     return new HtmlString(cdnPrefix + "/cached/" + Version + p); 
    } 

    public override async Task ProcessRequestAsync(HttpContext context) 
    { 
     var Response = context.Response; 
     Response.Cache.SetCacheability(HttpCacheability.Public); 
     Response.Cache.SetMaxAge(MaxAge); 
     Response.Cache.SetExpires(DateTime.Now.Add(MaxAge)); 

     if (CORSOrigins != null) 
     { 
      Response.Headers.Add("Access-Control-Allow-Origin", CORSOrigins); 
     } 


     string FilePath = context.Items["FilePath"] as string; 

     var file = new FileInfo(context.Server.MapPath("/" + FilePath)); 
     if (!file.Exists) 
     { 
      throw new FileNotFoundException(file.FullName); 
     } 

     Response.ContentType = MimeMapping.GetMimeMapping(file.FullName); 

     using (var fs = file.OpenRead()) 
     { 
      await fs.CopyToAsync(Response.OutputStream); 
     } 
    } 

    IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) 
    { 
     //FilePath = requestContext.RouteData.GetRequiredString("name"); 
     requestContext.HttpContext.Items["FilePath"] = requestContext.RouteData.GetRequiredString("name"); 
     return (IHttpHandler)this; 
    } 
} 

заголовкам Пример отклика для первого запроса

Access-Control-Allow-Origin:* 
Cache-Control:public 
Content-Length:453 
Content-Type:image/png 
Date:Sat, 04 Jul 2015 08:04:55 GMT 
Expires:Mon, 03 Aug 2015 00:46:43 GMT 
Server:Microsoft-IIS/8.5 
Via:1.1 ******************************** 
X-Amz-Cf-Id: ****************************** 
X-AspNet-Version:4.0.30319 
X-AspNetMvc-Version:5.2 
X-Cache:Miss from cloudfront 
X-Powered-By:ASP.NET 

See, нет ETag, Вар, заголовок проверки последнего изменения или, а также увидеть явное Истекает заголовок, когда вы отправляете явный заголовок Expires, браузер никогда не будет пытаться проверить кеш.

+0

Не могли бы вы показать мне заголовок ответа для первого запроса? –

0

Это простое решение с HttpModule, которое работает в реализациях ASP. Мы использовали его в приложении SPA. Он попросит браузер кэшировать определенные ресурсы в течение года. Исходная/целевая страница является исключением и всегда будет проверяться с помощью ETag.

Шаг 1: Первый шаг, который вы уже сделали, который добавляет номер версии в URL-адрес каждого ресурса. Мы делаем это как автоматизированный шаг в процессе сборки.

Шаг 2: Затем добавьте класс CacheModule в приложение:

public class CacheModule : IHttpModule 
    { 
     // extensions to cache, e.g. ".css",".html",".js",".png",".jpg",".gif",".ico",".woff",".eot",".svg",".ttf" 
     private readonly string[] _extensions = ConfigurationManager.AppSettings["CacheModule_Extensions"].Split(",");   


     private readonly string[] _exceptions = ConfigurationManager.AppSettings["CacheModule_Exceptions"].Split(","); 


     public void Dispose() {} 

     public void Init(HttpApplication context) 
     { 
      context.EndRequest += (sender, args) => 
      { 
       var ctx = HttpContext.Current; 
       var path = ctx.Request.Url.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped); 

       var isExcept = _exceptions.Any(path.Contains); 

       ctx.Response.AddHeader("Cache-Control", "private"); 

       if (_extensions.Any(path.Contains) && ! isExcept) 
       { 
        ctx.Response.AddHeader("Expires", (DateTime.Now.ToUniversalTime().AddYears(1)).ToString("r")); 
       } 
       else if (isExcept) 
       { 
        ctx.Response.AddHeader("Expires", (DateTime.Now.ToUniversalTime().AddHours(-1)).ToString("r")); 
        ctx.Response.AddHeader("Max-Age", "0"); 
       } 

      }; 
     } 


    } 

Шаг 3: Наконец вы положили в вашей конфигурации:

<?xml version="1.0"?> 
    <configuration> 
     <appSettings> 
      <!-- resource extensions to cache --> 
      <add key="CacheModule_Extensions" value=".css,.html,.js,.png,.jpg,.gif,.ico,.woff,.eot,.svg,.ttf" /> 
      <!-- exceptions to caching such as home/landing page e.g. "index.html" or any page/resource with known url that users may enter directly or may be redirected to --> 
      <add key="CacheModule_Exceptions" value="index.html,buildinfo.html,unsupportedmobilebrowser.html, unsupportedbrowser.html" /> 
     </appSettings> 
    <system.webServer> 
     <modules> 
      <add name="CacheModule" type="MyApp.Caching.CacheModule, MyApp"/> 
     </modules> 
    </system.webServer> 
</configuration> 
Смежные вопросы