Levier de mise en cache du navigateur dans IIS (google pagespeed question)
Il y a plusieurs questions à propos de tirant parti de la mise en cache du navigateur mais je n'ai pas trouvé quelque chose d'utile pour savoir comment faire cela dans un ASP.NET application. Google Pagespeed raconte cette performance est plus gros problème.
Jusqu'à présent je l'ai fait dans mon web.config:
<system.webServer>
<staticContent>
<!--<clientCache cacheControlMode="UseExpires"
httpExpires="Fri, 24 Jan 2014 03:14:07 GMT" /> -->
<clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="7.24:00:00" />
</staticContent>
</system.webServer>
Code commenté des œuvres. Je peux mettre à expiration en-tête pour être certain moment donné dans l'avenir, mais je n'étais pas en mesure de définir cacheControlMaxAge
pour définir le nombre de jours à partir de maintenant, le contenu statique serait mis en cache. Il ne fonctionne pas. Ma questions est:
Comment puis-je le faire?
Je sais qu'il est possible de configurer la mise en cache uniquement pour dossier spécifique qui serait une bonne solution, mais il ne fonctionne pas aussi. L'Application est hébergée sur un Serveur Windows server 2012,sur IIS8, l'application de la piscine est la valeur classique.
Après que j'ai mis ce code dans le web config j'ai eu pagespeed de 72 (avant était de 71). 50 fichiers n'ont pas été mis en cache. (Maintenant 49) je me demandais pourquoi et je viens de réaliser qu'un fichier a été effectivement mis en cache (fichier svg). Malheureusement, png et jpg fichier n'ont pas été.
C'est mon web.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="exceptionManagement" type="Microsoft.ApplicationBlocks.ExceptionManagement.ExceptionManagerSectionHandler,Microsoft.ApplicationBlocks.ExceptionManagement" />
<section name="jsonSerialization" type="System.Web.Configuration.ScriptingJsonSerializationSection, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E34" requirePermission="false" allowDefinition="Everywhere" />
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
<section name="errorMail" requirePermission="false" type="Elmah.ErrorMailSectionHandler, Elmah" />
<section name="errorFilter" requirePermission="false" type="Elmah.ErrorFilterSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<exceptionManagement mode="off">
<publisher mode="off" assembly="Exception" type="blabla.ExceptionHandler.ExceptionDBPublisher" connString="server=188......;database=blabla;uid=blabla;pwd=blabla; " />
</exceptionManagement>
<location path="." inheritInChildApplications="false">
<system.web>
<httpHandlers>
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler,System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e34" validate="false" />
<add verb="GET" path="Image.ashx" type="blabla.WebComponents.ImageHandler, blabla/>"
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
<add verb="*" path="*.jpg" type="System.Web.StaticFileHandler" />
<add verb="GET" path="*.js" type="System.Web.StaticFileHandler" />
<add verb="*" path="*.gif" type="System.Web.StaticFileHandler" />
<add verb="GET" path="*.css" type="System.Web.StaticFileHandler" />
</httpHandlers>
<compilation defaultLanguage="c#" targetFramework="4.5.1" />
<trace enabled="false" requestLimit="100" pageOutput="true" traceMode="SortByTime" localOnly="true"/>
<authentication mode="Forms">
<forms loginUrl="~/user/login.aspx">
<credentials passwordFormat="Clear">
<user name="blabla" password="blabla" />
</credentials>
</forms>
</authentication>
<authorization>
<allow users="*" />
</authorization>
<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes" cookieless="false" timeout="20" />
<globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="en-GB" uiCulture="en-GB" />
<xhtmlConformance mode="Transitional" />
<pages controlRenderingCompatibilityVersion="4.5" clientIDMode="AutoID">
<namespaces>
</namespaces>
<controls>
<add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
</controls>
</pages>
<webServices>
<protocols>
<add name="HttpGet" />
<add name="HttpPost" />
</protocols>
</webServices>
</system.web>
</location>
<appSettings>
</appSettings>
<connectionStrings>
</connectionStrings>
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization maxJsonLength="200000" />
</webServices>
</scripting>
</system.web.extensions>
<startup>
<supportedRuntime version="v2.0.50727" />
<supportedRuntime version="v1.1.4122" />
<supportedRuntime version="v1.0.3705" />
</startup>
<system.webServer>
<rewrite>
<providers>
<provider name="ReplacingProvider" type="ReplacingProvider, ReplacingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5ab632b1f332b247">
<settings>
<add key="OldChar" value="_" />
<add key="NewChar" value="-" />
</settings>
</provider>
<provider name="FileMap" type="DbProvider, Microsoft.Web.Iis.Rewrite.Providers, Version=7.1.761.0, Culture=neutral, PublicKeyToken=0525b0627da60a5e">
<settings>
<add key="ConnectionString" value="server=;database=blabla;uid=blabla;pwd=blabla;App=blabla"/>
<add key="StoredProcedure" value="Search.GetRewriteUrl"/>
<add key="CacheMinutesInterval" value="0"/>
</settings>
</provider>
</providers>
<rewriteMaps configSource="rewritemaps.config" />
<rules configSource="rewriterules.config" />
</rewrite>
<modules>
<remove name="ScriptModule" />
<add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3456AD264E35" />
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
</modules>
<handlers>
<add name="Web-JPG" path="*.jpg" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
<add name="Web-CSS" path="*.css" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
<add name="Web-GIF" path="*.gif" verb="GET,HEAD,POST" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
<add name="Web-JS" path="*.js" verb="GET,HEAD,POST,DEBUG" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" preCondition="classicMode,runtimeVersionv4.0,bitness64" />
</handlers>
<validation validateIntegratedModeConfiguration="false" />
<httpErrors errorMode="DetailedLocalOnly" existingResponse="Auto">
<remove statusCode="404" subStatusCode="-1"/>
<remove statusCode="500" subStatusCode="-1"/>
<error statusCode="404" path="error404.htm" responseMode="File"/>
<error statusCode="500" path="error.htm" responseMode="File"/>
</httpErrors>
</system.webServer>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="soapBinding_AdriagateService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true" messageEncoding="Text">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</basicHttpBinding>
<netTcpBinding>
<binding name="NetTcpBinding_ITravellerService" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
<security mode="None" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="blabla" bindingConfiguration="soapBinding_blabla" contract="" Address="blabla" name="blabla" />
<endpoint address="blabla" binding="basicHttpBinding" bindingConfiguration="soapBinding_IImagesService"
contract="ImagesService.IImagesService" name="soapBinding_IImagesService"/>
<identity>
<servicePrincipalName value="blabla"/>
</identity>
</endpoint>
</client>
</system.serviceModel>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-1.5.2.14234" newVersion="1.5.2.14234" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.5.0.0" newVersion="4.5.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.web>
<httpModules>
<add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
<add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
<add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
</httpModules>
</system.web>
<elmah>
<security allowRemoteAccess="false" />
</elmah>
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
</handlers>
</system.webServer>
</location>
</configuration>
EDIT:
Si j'ai mis exacte de la date d'expiration, la mise en cache est à travailler, mais pas pour jpg,gif....uniquement pour les png
EDIT2:
Si j'ai mis cacheControlCustom="public"
comme ici:
<clientCache cacheControlCustom="public"
cacheControlMode="UseMaxAge" cacheControlMaxAge="7.00:00:00" />
la mise en cache est un travail, mais encore pas pour les jpeg et gif; il ne fonctionne que pour svgs et png.
- Est-il un programme ou service qui modifie ou qui touche votre jpg/gif fichiers?
Vous devez vous connecter pour publier un commentaire.
Plus de la mise en cache du navigateur problèmes peuvent être résolus en consultant les en-têtes de réponse (peut être fait dans Google chrome developer tools).
Maintenant la
clientCache
section de votreweb.config
fichier doit configurer votre mise en cache de sortie à un âge maximal que vous voyez dans l'image ci-dessous a mis lemax-age
à86400
qui est de 1 jour en quelques secondes.Ici, c'est le web.config extrait de code pour cette installation.
Maintenant c'est génial, l'en-tête de réponse a un
max-age
propriété définie sur laCache-Control
en-tête. Ainsi, le navigateur devrait mise en cache le contenu. Eh bien c'est surtout vrai, mais certains navigateurs exiger d'un autre indicateur à définir. Plus précisément lepublic
indicateur est défini pour le cache de la tête de contrôle. Ceci peut être facilement ajoutés à l'aide de lacacheControlCustom
attribut dans laweb.config
. Ici est un exemple.Maintenant, quand nous réessayer la page et d'inspecter les en-têtes.
Maintenant, comme vous pouvez le voir sur l'image ci-dessus, nous avons maintenant la valeur
public, max-age=86400
. Donc, notre navigateur a besoin pour mettre en cache les ressources. Maintenant examiner les en-têtes et le réseau de l'onglet de google chrome va nous aider.Ici à la première demande pour le fichier.. Note le fichier n'est pas mis en cache...
Maintenant permet de revenir à cette page (REMARQUE: ne pas rafraîchir la page, nous allons parler que dans une seconde). Vous verrez la réponse en retour du cache (comme entourée d'un cercle).
Maintenant ce qui se passe si j'actualise la page en utilisant soit F5 ou en utilisant le navigateur de la fonctionnalité d'actualisation. Attendre.. d'où vient le
(from cache)
aller.Bien dans Google Chrome (pas sûr sur les autres navigateurs) en utilisant le bouton de rafraîchissement de re-télécharger les ressources statiques, quel que soit le cache de l'en-tête (insérer des précisions s'il vous plaît ici). Cela signifie que les ressources a été récupérée et l'âge maximum de l'en-tête envoyé plus de.
Maintenant, après toutes les explications ci-dessus, assurez-vous de tester comment de monitoring des en-têtes de cache.
Mise à jour
En fonction de vos commentaires vous avez dit que vous avez un générique gestionnaire (
IHttpHandler
) nomméImage.ashx
avec le type de contenu deimage/jpg
. Maintenant, vous pouvez vous attendre le comportement par défaut serait de mettre en cache ce gestionnaire. Cependant IIS voit dans l'extension.ashx
(correctement) comme un script dynamique et n'est pas assujettie à la mise en cache sans définir explicitement les en-têtes de cache dans le code lui-même.Maintenant, c'est là où vous devez être prudent, car généralement
IHttpHandlers
doit en effet pas être mis en cache, car ils sont généralement fournir du contenu dynamique. Maintenant, si ce contenu est peu susceptible de changer, vous pouvez faire de vos en-têtes de cache directement dans le code. Voici un exemple de création d'en-têtes de cache dansIHttpHandlers
à l'aide de laResponse
contexte.Maintenant à la recherche du code, nous nous donnons quelques propriétés sur les
Cache
de la propriété. Pour obtenir la réponse désirée, j'ai mis les propriétés.context.Response.Cache.SetMaxAge(TimeSpan.FromDays(1));
raconte les mettre à cache pour définir lamax-age=
partie de laCache-Control
- tête pour être1
jour dans le futur (86400 secondes).context.Response.Cache.SetCacheability(HttpCacheability.Public);
raconte les mettre à cache pour définir laCache-Control
en-tête depublic
. Ceci est très important car il indique au navigateur d'cache d'objet.context.Response.Cache.SetSlidingExpiration(true);
dit le cache de sortie pour s'assurer qu'il est le réglage de lamax-age=
partie de laCache-Control
en-tête correctement. Sans réglage de l'expiration glissante, IIS mettre en cache ignore l'âge maximum de l'en-tête. Mettre cela ensemble me donne ce résultat.Comme je l'ai dit ci-dessus, vous ne voulez pas mettre en cache les
.ashx
fichiers comme il est de règle fournir du contenu dynamique. Par contre si dynamique le contenu n'est pas susceptible de changer d'une période donnée, vous pouvez utiliser les méthodes ci-dessus pour livrer votre.ashx
fichier.Maintenant en conjonction avec le processus énumérés ci-dessus, vous pouvez aussi définir la ETag (voir wiki) de la composante en-têtes de cache pour le navigateur peut vérifier le contenu transmis par une chaîne personnalisée. Le wiki états:
Donc c'est vraiment une sorte d'identification unique pour le navigateur pour identifier le contenu livré dans la réponse. En offrant cet en-tête du navigateur sur le prochain rechargement envoie un
If-None-Match
en-tête avec leETag
de la dernière réponse. Nous pouvons modifier notre gestionnaire de détecter laIf-None-Match
en-tête et de le comparer à nos propres généréesEtag
. Maintenant, il n'y a pas de science exacte pour générerETags
mais une bonne règle de base est de fournir un identifiant qui sera plus susceptible de ne définir qu'une seule entité. Dans ce cas, je préfère utiliser deux chaînes concaténées ensemble tels que.Dans l'extrait ci-dessus, nous sommes le chargement d'un fichier à partir de notre système de fichiers (vous pouvez obtenir ce à partir de n'importe où). Je suis alors à l'aide de la
GetHashCode()
méthode (sur tous les objets) pour obtenir le nombre entier le code de hachage de l'objet. Dans l'exemple que j'ai concat le hachage du fichier, le nom de la dernière écriture de la date. La raison de la date de la dernière écriture est dans le cas où le fichier est modifié, le code de hachage est changé, rendant ainsi le traces de doigts différents.Cela va générer un code de hachage similaire à
306894467-210133036
.Alors, comment faisons-nous dans notre gestionnaire. Ci-dessous est la nouvelle version modifiée du gestionnaire.
Comme vous pouvez le voir, j'ai bien changé beaucoup de la gestionnaire cependant, vous remarquerez que nous générons la
Etag
de hachage, vérifier la réception duIf-None-Match
en-tête. Si l'etag hachage et la tête sont à égalité, puis nous dire au navigateur que le contenu n'en a pas changé par retourner le code d'état304 Not Modified
.Suivante, c'était le même gestionnaire d'exception, nous ajoutons la
ETag
- tête en appelant:Lors de l'exécution de cette opération dans le navigateur, nous obtenons.
Vous pouvez le voir dans l'image (comme je l'ai fait changer le nom du fichier) que nous avons maintenant toutes les composantes de notre système de cache en place. Le
ETag
est livré comme un en-tête, et le navigateur est l'envoi de l'en-tête de demandeIf-None-Match
donc, notre maître-chien peut réagir en conséquence pour fichier de cache changé.ETag
etLast-Modified
en-têtes. Je peux faire une écriture sur que sur une autre question, mais est assez simple. RegardezOutput Caching
dans IISDe l'utiliser. Ce qui fonctionne pour moi.
À l'aide de ce qui précède, le contenu statique fichiers seront mis en cache pendant 10 jours dans le navigateur. Des informations détaillées sur la
<clientCache>
élément peut être trouvé ici.Vous pouvez également utiliser le
<location>
élément de définir les paramètres du cache pour un fichier spécifique: