Добавить комментарий

Всем известна проблема с тем, что IE пытается кешированть больше чем нужно, и из-за этого возникают проблемы с ajax. Хочу рассказать, как решать эту проблему, используя связку ASP.NET MVC + jQuery. Итак суть задачи:

Браузер Internate Explorer кеширует обращения к серверу и из-за этого ajax-запросы возвращают некорректные результаты.

Варианты решения:

1 Использовать POST вместо GET

Считается, что IE кеширует только GET-запросы, поэтому достаточно переключиться на POST и всё заработает. На самом деле это не совсем так.

Во-первых, не всегда можно легко заменить GET на POST. Например, в ASP.NET MVC типичным является приём, когда создается пара методов — один 1 реагирует на GET и возвращяет разметку, другой 2 принимает POST и осуществляет некоторую операцию:

public class UserController
{
    public ActionResult New()               1
    {
        return View();
    }

    [HttpPost]
    public ActionResult New(UserForm form)  2
    {
        UserService.CreateNewUser(form);
        return View();
    }
}

Если через ajax требуется получить разметку из 1, то понятно, что на POST переключиться не получится.

Во-вторых, установлено, что IE кеширует даже POST-запросы в том случае, если POST не содержит никаких параметров.

2 Запретить кеширование на стороне сервера

Можно запретить кеширование на уровне сервера. В WebForms это делалось так:

Response.CacheControl = "no-cache";
Response.AddHeader("Pragma", "no-cache");
Response.Expires = -1;

Однако, некоторые утверждают, что такой способ для них не работает. В MVC можно использовать фильтр, например тот который сделал Jan Willem Boer:

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Web;  
using System.Web.Mvc;  

namespace YourNameSpaceHere  
    public class BrowserCacheAttribute : ActionFilterAttribute  
    {  
       /// <summary>  
       /// Gets or sets the cache duration in seconds.   
       /// The default is 10 seconds.  
       /// </summary>  
       /// <value>The cache duration in seconds.</value>  
       public int Duration  
       {  
           get;  
           set;  
       }  

       public bool PreventBrowserCaching   
       {   
           get;   
           set;   
       }  

       public BrowserCacheAttribute()  
       {  
           Duration = 10;  
       }  

       public override void OnActionExecuted(  
         ActionExecutedContext filterContext)  
       {  
           if (Duration < 0) return;  

           HttpCachePolicyBase cache = filterContext.HttpContext  
             .Response.Cache;  

           if (PreventBrowserCaching)  
           {  
               cache.SetCacheability(HttpCacheability.NoCache);  
               Duration = 0;  
           }  
           else  
           {  
               cache.SetCacheability(HttpCacheability.Public);  
           }  

           TimeSpan cacheDuration = TimeSpan.FromSeconds(Duration);  
           cache.SetExpires(DateTime.Now.Add(cacheDuration));  
           cache.SetMaxAge(cacheDuration);  
           cache.AppendCacheExtension("must-revalidate,"  
             + "proxy-revalidate");  
       }  
   }  
}

Хотя этот подход самый прямой, у него тоже есть недостаток. В ASP.NET MVC один и тот же метод контроллера часто используется для получения и основной страницы и её части через ajax:

public ActionResult New()
{
    if (Request.IsAjaxRequest())
    {
        return /* возвращаем ajax-результат */;
    }

    return /* возвращаем обычный результат */;
}

Если пометить метод New атрибутом BrowserCacheAttribute, то кеширование отменится и для обычных и для ajax-запросов. Это не совсем правильно. Нам нужно управлять только кешируемостью ajax-запроса, не трогая основную страницу. Вернее, нам нужно чтобы ajax-запрос возвращал всегда новый результат, даже если основная страница закеширована браузером.

3 Дополнительный параметр в запросе

Это самый действенный способ. Добавляем в список параметров какое-нибудь уникальное значение — и сам запрос также считается уникальным и не кешируется. В качестве уникального значения обычно используется timstamp:

$.ajax({
    type: "GET",
    url: "/users/list",
    data: { tstamp: new Date().getTime() },
    /* ... */
});

4 Использовать поддержку jQuery

Функция jQuery $.ajax в качестве одного из аргуметнов принимает параметр cache (Boolean). Если cache=false, то jQuery автоматически добавит к запросу уникальный параметр (тот же timestamp). То есть приведенный выше код можно записать следующим образом:

$.ajax({
    type: "GET",
    url: "/users/list",
    cache: false,
    /* ... */
});

Тут подводный камень в том, что если используется POST вместо GET, то jQuery опускает этот самый уникальный параметр за (якобы) ненужностью. То есть, если запрос посылается через GET, то можно смело использовать cache: false, но если запрос — это POST без параметров, то придется добавлять что-то типа data: { tstamp: new Date().getTime() }.

Progg it

Внимание! Вы собираетесь отправить информацию от имени анонимного пользователя.
v1.7.123.556
© 2009—2010 CodeHelper FAQ | О сайте | Обратная связь | История изменений | Статьи
Creative Commons LicenseМатериалы сайта распространяются под лицензией Creative Commons Attribution-Share Alike 3.0 Unported.