web-dev-qa-db-fra.com

Comment empêcher une demande qui retourne 304

Quand un navigateur ne demande PAS un fichier au serveur?

En d'autres termes, j'ai un fichier JavaScript en cours de service. Son en-tête de réponse HTTP a une ETag, Cache-Control: public et Expires: Tue, 19 Jan 2038 03:14:07 GMT.

Le serveur renvoie un 304 après l’amorçage du cache du navigateur.

Ma question est la suivante: pourquoi le navigateur vérifie-t-il même auprès du serveur et obtient-il un 304? Je ne veux pas que le navigateur demande s'il y a une nouvelle version. Il doit se charger directement à partir du cache du navigateur sans vérifier les modifications apportées par le serveur qui dessert le script.

Quelle combinaison d'en-têtes de réponse HTTP accomplit ceci?

51
core

Premièrement, la spécification HTTP pertinente est RFC 7234 . Si vous regardez les spécifications, vous remarquerez deux choses:

  • La spécification jamais exige , en aucun cas, qu’un cache serve une version mise en cache du contenu sans revalidation. Il y a de nombreux endroits où la spécification indique qu'un cache NE DOIT PAS utiliser de contenu mis en cache pour satisfaire une demande, mais pas du tout où il est obligé de le faire ou de NE PAS revalider. Les vendeurs de navigateurs sont donc toujours libres de revalider s'ils le souhaitent.
  • Deuxièmement, vous ne faites rien de mal de votre côté. Les navigateurs sont libres de mettre en cache les réponses et de les utiliser, en fonction des en-têtes que vous renvoyez. Le point clé se trouve dans Section 4 , où il est noté que l’une des conditions pour fournir une réponse en cache est que la réponse est soit:

    • frais (voir section 4.2), ou

    • autorisé à être servi éventé (voir section 4.2.4), ou

    • validé avec succès (voir section 4.3).

    Puisque vous crachez un en-tête Expires qui est loin dans le futur et que ce point dans le futur n’a pas encore été atteint, la réponse est "fraîche" et la revalidation n’est donc pas requise. Donc, vous faites tout ce que les spécifications suggèrent que vous devriez être sur votre fin. (Bien que l'utilisation de Cache-Control: max-age=foo soit un moyen plus moderne de définir les heures d'expiration du cache que d'utiliser l'en-tête Expires:.)

Donc, si vous voulez changer le comportement de mise en cache des navigateurs, vous n’avez pas de chance.

Cependant , les choses pourraient ne pas être aussi mauvaises que vous le pensez. Vous ne voyez probablement qu'une requête et 304 car vous actualisez la page de votre navigateur lors des tests. Les navigateurs traitent les ressources en cache différemment selon la façon dont la demande les concernant a été déclenchée.

J'ai exécuté un test simple dans lequel j'ai créé une page HTML contenant une balise <script> pointant vers un fichier JS, une balise <img> pointant vers une image et une balise <link> pointant vers une feuille de style CSS. Tous ces fichiers ont été hébergés sur un serveur Apache configuré pour les desservir avec:

  • un en-tête E-Tag,
  • une date de dernière modification,
  • un en-tête Cache-Control: max-age=172800

Naturellement, toutes les ressources ont été servies avec 200 codes lors du chargement de la première page. Par la suite, en testant dans Chrome ou Firefox installe avec les paramètres par défaut, j'ai observé que:

  • Si vous actualisez la page via le F5 touche ou le bouton Actualiser , la page et toutes les ressources revalidées (c’est-à-dire qu’une demande est faite au serveur pour chaque ressource et qu’une 304 est renvoyée).
  • Si vous revenez à la page via un lien ou en entrant l'URL dans la barre d'URL dans un nouvel onglet, alors aucune revalidation n'est effectuée (c'est-à-dire qu'aucune demande n'est demandée. fabriqué).
  • Dans Chrome, si vous actualisez la page en sélectionnant la barre d'URL et en appuyant sur Entrée, la page elle-même se revalide, mais aucune autre ressource ne le fait. Dans Firefox, ni la page ni les ressources ne sont validées.

Cette page indique qu'Internet Explorer a le même comportement:

Internet Explorer doit vérifier si une entrée mise en cache est valide dans un certain nombre de situations:

  • L'entrée en cache n'a pas de date d'expiration et le contenu est en cours d'accès pour la première fois dans une session de navigateur.
  • L'entrée mise en cache a une date d'expiration mais elle a expiré
  • L'utilisateur a demandé une mise à jour de page en cliquant sur le bouton Actualiser ou en appuyant sur F5.

En d'autres termes, vous ne verrez généralement ces demandes de revalidation que si l'utilisateur actualise explicitement la page. À moins d’exigences particulières quant à la manière dont vous voulez que le cache du navigateur se comporte, ce comportement semble parfaitement raisonnable.

Google et Mozilla ont tous deux de la documentation sur la mise en cache HTTP (je ne trouve rien d’équivalent sur MSDN ou sur le site Apple Developers), mais ni ne suggère l’existence d’un fournisseur quelconque. des en-têtes de mise en cache spécifiques pouvant être utilisés pour modifier les règles utilisées par le navigateur pour choisir le moment de la revalidation. Ce que vous voulez faire est tout simplement impossible.

Si vous avez vraiment besoin de plus de contrôle sur ce comportement, vous pouvez consulter cache d’application HTML5 ou lancer votre propre logique de mise en cache à l’aide du stockage local HTML5, comme le fait basket.js .

87
Mark Amery

Expires: ou Cache-Control: max-age= devrait fonctionner. Avez-vous confirmé dans les journaux du serveur que le navigateur passe réellement des appels réseau? J'ai constaté que firebug, par exemple, produisait une sortie déroutante, ce qui suggère que vous effectuez des appels à distance lorsque vous atteignez le cache. 

0
James Scriven

Si vous êtes dans mon bateau et qu'une application angulaire est déployée sur IIS, assurez-vous que votre configuration web est configurée pour réécrire correctement l'URL, comme suit:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <httpErrors errorMode="Detailed" />
        <rewrite>
            <rules>
                <rule name="Angular Routes" stopProcessing="true">
                    <match url=".*" />
                    <conditions logicalGrouping="MatchAll">
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/NameOfYourApp_UnderDefaultWebSite/" />
                </rule>
            </rules>
        </rewrite>
  </system.webServer>
</configuration>

Notez spécifiquement la valeur de l'URL dans <action type="Rewrite" url="/NameOfYourApp_UnderDefaultWebSite/" />

0
Adam Cox