web-dev-qa-db-fra.com

Contrôle du cache: no-store, must-revalidate non envoyé au navigateur client dans IIS7 + ASP.NET MVC

J'essaie de m'assurer qu'une page donnée n'est jamais mise en cache et ne s'affiche jamais lorsque l'utilisateur clique sur le bouton Précédent. Cette réponse très bien noté (actuellement 1068 votes positifs) dit d'utiliser :

Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

Cependant, dans IIS7/ASP.NET MVC, lorsque j'envoie ces en-têtes, le client voit alors ces en-têtes de réponse:

Cache-control: private, s-maxage=0 // that's not what I set them to
Pragma: no-cache
Expires: 0

Qu'est-il arrivé à l'en-tête de contrôle du cache? Est-ce que quelque chose natif à IIS7 ou ASP.NET l'écrase? J'ai vérifié ma solution et je n'ai aucun code qui écrase cet en-tête.

Quand j'ajoute Response.Headers.Remove("Cache-Control"); en premier, cela ne fait aucune différence:

Response.Headers.Remove("Cache-Control");
Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

Quand j'ajoute un attribut [OutputCache]:

[OutputCache(Location = OutputCacheLocation.None)]
public ActionResult DoSomething()
{
   Response.Headers.Remove("Cache-Control");
   Response.AppendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
   Response.AppendHeader("Pragma", "no-cache");
   Response.AppendHeader("Expires", "0");

   var model = DoSomething();
   return View(model);
}

Ensuite, les en-têtes de réponse du client deviennent:

Cache-control: no-cache
Pragma: no-cache
Expires: 0

Ce qui est plus proche, mais toujours pas les en-têtes que je veux envoyer. Où ces en-têtes sont-ils remplacés et comment puis-je l'arrêter?

EDIT: j'ai vérifié et les en-têtes incorrects sont envoyés à Chrome, FF, IE et Safari. Il semble donc s'agir d'un problème de serveur, pas d'un problème lié au navigateur.

23
JK.

Après des essais et des erreurs, j'ai constaté que l'une des méthodes permettant de définir correctement les en-têtes pour IIS7 dans ASP.NET MVC consiste à:

Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.AppendCacheExtension("no-store, must-revalidate");
Response.AppendHeader("Pragma", "no-cache");
Response.AppendHeader("Expires", "0");

La première ligne définit Cache-control sur no-cache et la deuxième ligne ajoute les autres attributs no-store, must-revalidate.

Ce n'est peut-être pas le seul moyen, mais fournit une méthode alternative si la fonction plus simple Response.AppendHeader("Cache-control", "no-cache, no-store, must-revalidate"); échoue.

Les autres questions liées au contrôle du cache IIS7 qui peuvent être résolues par ceci sont:

36
JK.

Si vous avez besoin de ces en-têtes globalement dans votre application MVC. Ajoutez cette classe.

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class CustomHeaders : System.Web.Mvc.ActionFilterAttribute
{
    [OutputCache(Location = System.Web.UI.OutputCacheLocation.None)]
    public override void OnActionExecuted(ActionExecutedContext context)
    {
        context.RequestContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        context.RequestContext.HttpContext.Response.Cache.AppendCacheExtension("no-store, must-revalidate");
        context.RequestContext.HttpContext.Response.AppendHeader("Pragma", "no-cache");
        context.RequestContext.HttpContext.Response.AppendHeader("Expires", "0");

        base.OnActionExecuted(context);
    }
}

Pour une utilisation globale, ajoutez-le à FilterConfig.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new CustomHeaders());
    }
}

Ou utilisez uniquement ces en-têtes sur un contrôleur spécifique.

[Authorize]
[CustomHeaders]
public class HomeController : Controller
{
    [AllowAnonymous]
    public ActionResult Index()

Remarque secondaire: vous pouvez utiliser IIS et web.config pour d’autres en-têtes. Par exemple, sur du contenu statique comme vos bundles (jquery, bootstrap). Recherchez ces sections customheaders, staticcontent.

0
ivw

Je veux ajouter quelque chose à la réponse de JK :
Si vous définissez le contrôle du cache sur une valeur plus restrictive que celle-ci, tout va bien. (c'est-à-dire: mettre no-cache, quand c'est privé) 

Toutefois, si vous souhaitez définir une valeur moins restrictive qu'elle ne l'est déjà (c'est-à-dire, définissez-le sur privé, sans cache), le code ci-dessous ne fonctionnera pas: 

Response.Cache.SetCacheability(HttpCacheability.Private);

En effet, la méthode SetCacheablitiy a ce code ci-dessous et active l'indicateur de cache uniquement s'il est plus restrictif: 

if (s_cacheabilityValues[(int)cacheability] < s_cacheabilityValues[(int)_cacheability]) {
    Dirtied();
   _cacheability = cacheability;
}

Pour résoudre ce problème dans .net mvc, vous devez obtenir une instance de HttpResponseMessage et affecter une valeur CacheControlHeaderValue à sa valeur Headers.CacheControl

actionExecutedContext.Response.Headers.CacheControl = new CacheControlHeaderValue
                                   {
                                       MaxAge = TimeSpan.FromSeconds(3600),
                                       Private = true
                                   };

Une instance de HttpResponseMessage est disponible dans les filtres d'action. Vous pouvez écrire un filtre d'action pour définir les valeurs d'en-tête de cache comme suit: 

public class ClientSideCacheAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {
        var response = actionExecutedContext.ActionContext.Response;
        response.Headers.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue
        {
            MaxAge = TimeSpan.FromSeconds(9999),
            Private = true,
        };
    }
}
0
Veysel Özdemir