Предотвращение кеширования браузером результата вызова AJAX

262

Похоже, что если я загружаю динамический контент $.get(), результат кэшируется в браузере.

Добавление некоторой случайной строки в QueryString, кажется, решает эту проблему (я использую new Date().toString()), но это похоже на хак.

Есть ли другой способ добиться этого? Или, если уникальная строка - единственный способ добиться этого, есть какие-то предложения, кроме new Date()?

Salamander2007
источник
Вы можете использовать короткие обозначения $.now()вместо выполнения (new Date (). GetTime ()) каждый раз.
Дейсон
1
Название вашего вопроса немного вводит в заблуждение. Можете ли вы рассмотреть его переименование?
0112
4
Рассматривали ли вы выбор другого ответа в качестве принятого?
M4N

Ответы:

241

Я использую new Date().getTime(), что позволит избежать коллизий, если у вас есть несколько запросов, происходящих в течение одной миллисекунды:

$.get('/getdata?_=' + new Date().getTime(), function(data) {
    console.log(data); 
});

Изменить: этому ответу несколько лет. Это все еще работает (следовательно я не удалил это), но есть лучшие / более чистые способы достигнуть этого теперь . Я предпочитаю этот метод, но этот ответ также полезен, если вы хотите отключить кэширование для каждого запроса во время жизни страницы.

Марк Белл
источник
11
Я буду опускать голоса только потому, что позволить jQuery делать это чище, как в ответе Питера Дж. Ваше решение будет работать, но его будет труднее поддерживать в долгосрочной перспективе.
Никлас Вульф
11
Какая часть этого требует обслуживания? По сравнению с тем, что делает JQuery?
Санни Р Гупта
5
Может быть , стоит отметить , что new Date().getTime()код используется как это ... var nocache = new Date().getTime(); var path = 'http://hostname.domain.tld/api/somejsonapi/?cache=' + nocache;. Мне потребовалось несколько минут, чтобы понять это сам. Конечно, это ?cacheможет быть любая формулировка, которую API на самом деле не хочет.
дваждыJ
1
+1 даже ответ Питера Дж. С лучшим подходом к этому ответу не ошибочный и не плохой. Я считаю, что DV сделаны, потому что ваш выше Питера (как принято). и ОП не появляется на SO с начала 2013 года
Мишель Айрес
1
url = url + (-1 === url.indexOf('?') ? '?' : '&') + "__=" + Number(new Date());
514

Следующее действие предотвратит кэширование всех будущих запросов AJAX независимо от того, какой метод jQuery вы используете ($ .get, $ .ajax и т. Д.)

$.ajaxSetup({ cache: false });
Питер Дж
источник
7
После расследования (Fiddler), похоже, что jQuery реализует это внутренне, просто добавив временную метку в любом случае (как обсуждалось в других местах этих ответов). Для меня метод .ajaxSetup чище (на мой взгляд.)
Питер Дж
8
Действительно, не нужно быть внутри документа готовым к вызову.
Питер Дж
19
Зачем отключать кеширование ajax глобально? Я думаю, что это должно быть сделано для каждого звонка, как и ответ Джонатана.
Санни Р Гупта
5
Все, что работает для вашего приложения. Я продолжаю использовать этот метод в коммерческих приложениях, когда мне абсолютно необходимы свежие данные для всех вызовов AJAX. Для других, кешированные данные хорошо.
Питер Дж
1
ссылка Описание: Установите значения по умолчанию для будущих запросов Ajax. Его использование не рекомендуется.
itwebdeveloper
319

$ .Get () JQuery будет кэшировать результаты. Вместо того

$.get("myurl", myCallback)

вы должны использовать $ .ajax, который позволит вам отключить кеширование:

$.ajax({url: "myurl", success: myCallback, cache: false});
Джонатан Моффат
источник
62
+1 Это правильный ответ. Решение Питера J о глобальном отключении кэширования является плохой практикой IMO.
Салман фон Аббас
7
Важно отметить, что это только «глобальный» для страницы / запроса.
Питер Дж
3
+1: кеширование должно соответствовать типу запроса. Для некоторых запросов к серверу может потребоваться кэширование (где данные сервера статичны), поэтому выбор кэширования для запроса по запросу лучше, чем просто отключить его .
Ушел кодирование
1
+1 за правильный ответ - предотвращение кэширования на основе вызова с использованием метода jQuery, а не ручного взлома.
Брендан Хилл
2
Еще один хороший ответ. Я должен сказать, что для меня большая часть времени, когда глобальное отключение кеша приносит большую пользу. Однако все зависит от того, как разработано ваше приложение. Серебряной маркировки нет, но в этой ситуации я бы порекомендовал функцию, которая принимает логическое значение для кэширования, функцию для обратного вызова и URL-адрес для модульности. Руководство "взломать" хорошо, но если вы используете jQuery, придерживайтесь их функций всякий раз, когда это возможно. Это облегчит не только разработку, но и будущие обновления библиотеки.
Энтони Мейсон
24

Все ответы здесь оставляют след на запрошенном URL, который будет отображаться в журналах доступа сервера.

Мне нужно было решение на основе заголовков без побочных эффектов, и я обнаружил, что этого можно добиться, установив заголовки, упомянутые в разделе Как контролировать кэширование веб-страниц во всех браузерах? ,

Результат, по крайней мере, для Chrome:

$.ajax({
   url: url, 
   headers: {
     'Cache-Control': 'no-cache, no-store, must-revalidate', 
     'Pragma': 'no-cache', 
     'Expires': '0'
   }
});

Помощь в
источник
Возможно глупый вопрос, но если мой ajax вернет изображения, будут ли изображения кэшироваться? Чтобы избежать массивных запросов Amazon S3?
Марсело Агимовел
MarceloAgimóvel, это может быть отдельный вопрос SO, я верю.
Айдин
23

Другой способ - не предоставлять заголовки кэша со стороны сервера в коде, который генерирует ответ на вызов ajax:

response.setHeader( "Pragma", "no-cache" );
response.setHeader( "Cache-Control", "no-cache" );
response.setDateHeader( "Expires", 0 );
miceuz
источник
17
Неправильно. В IE заголовки без кэширования игнорируются для вызовов XMLHttpRequest, как обсуждено здесь: stackoverflow.com/questions/244918/… DateTime (или мой метод .ajaxSetup) являются единственными решениями, которые действительно работают.
Питер Дж
я только что вставил свою обычную
заклинание
2
Это должно отключить кэширование для всех браузеров: response.setHeader («Cache-Control», «max-age = 0, no-cache, no-store, post-check = 0, pre-check = 0»);
Крис Броски
13

Лично я чувствую, что метод строки запроса более надежен, чем попытка установить заголовки на сервере - нет гарантии, что прокси или браузер все равно не просто кеширует его (некоторые браузеры хуже других - не называя имен).

Я обычно использую, Math.random()но я не вижу ничего плохого в использовании даты (вам не следует выполнять запросы AJAX достаточно быстро, чтобы получить одно и то же значение дважды).

Greg
источник
2
Объедините Date (). GetTime () вместе с Math.random (), и вы должны быть в безопасности. В дополнение к этому, Ext.Ajax также использует getTime (), когда указано disableCaching.
Vividos
12

Следующая документация: http://api.jquery.com/jquery.ajax/

Вы можете использовать cacheсвойство с:

$.ajax({
    method: "GET",
    url: "/Home/AddProduct?",
    data: { param1: value1, param2: value2},
    cache: false,
    success: function (result) {
        // TODO
    }
});
MrMins
источник
5

Конечно, методы «взлома кеша» выполнят работу, но в первую очередь этого не произойдет, если сервер сообщит клиенту, что ответ не должен кэшироваться. В некоторых случаях полезно кэшировать ответы, иногда нет. Пусть сервер решит правильное время жизни данных. Вы можете изменить это позже. Гораздо проще сделать это с сервера, чем из разных мест в вашем коде пользовательского интерфейса.

Конечно, это не поможет, если у вас нет контроля над сервером.

Марк Ренуф
источник
5

Как насчет использования запроса POST вместо GET ...? (Что вы все равно должны ...)

Томас Хансен
источник
Я думаю, что это лучшее решение, но, к сожалению, я (как-то) могу только сделать запрос GET. Так что .. теперь это новый Date (). GetTime ().
Salamander2007
Пожалуйста, добавьте пояснения к своему ответу, чтобы другие могли извлечь из него урок - зачем нужен запрос POST?
Нико Хаас
5

На самом деле вопрос в том, зачем вам это не кэшировать. Если он не должен кэшироваться, потому что он все время меняется, сервер должен указать, что не следует кэшировать ресурс. Если он просто иногда изменяется (потому что может измениться один из ресурсов, от которого он зависит), и если клиентский код имеет возможность узнать об этом, он может добавить фиктивный параметр к URL-адресу, который вычисляется по некоторому хэшу или дате последнего изменения из этих ресурсов (это то, что мы делаем в ресурсах сценариев Microsoft Ajax, чтобы они могли кэшироваться вечно, но новые версии могут по-прежнему обслуживаться по мере их появления). Если клиент не может знать об изменениях, сервер должен правильно обрабатывать запросы HEAD и сообщать клиенту, использовать кэшированную версию или нет. Мне кажется, что добавление случайного параметра или указание от клиента никогда не кэшировать - это неправильно, потому что кэшируемость является свойством ресурса сервера, и поэтому следует принимать решение на стороне сервера. Другой вопрос, который нужно задать себе: должен ли этот ресурс действительно обслуживаться через GET или он должен проходить через POST? Это вопрос семантики, но он также имеет последствия для безопасности (существуют атаки, которые работают, только если сервер допускает GET). POST не будет кэшироваться.


источник
6
Что если вы используете прокси-серверы, которые не контролируют их политику кэширования? Что если вашему приложению явно нужно каждый раз делать новый запрос? Ответом на вещи не всегда является четкое черно-белое изображение, всегда присутствуют серые участки.
7
Правда, это не всегда ясно. Но, увидев этот ответ, я усомнился в своих предположениях и нашел причину своей проблемы. Это может быть не для всех, но это помогло мне. Если вы здесь читаете это, вы должны рассмотреть это также.
Джонатан Тран
Это мне помогло, ResponseCaching был установлен на стороне сервера 60 м по умолчанию. Изменил его на No-Cache, и он прекратил кэширование на клиенте.
Мэттиджи
4

Возможно, вам следует взглянуть на $ .ajax () (если вы используете jQuery, как это выглядит). Взгляните на: http://docs.jquery.com/Ajax/jQuery.ajax#options и опцию «кеш».

Другой подход - посмотреть, как вы кешируете вещи на стороне сервера.

finpingvin
источник
1
К сожалению, после некоторого исследования использование $ .ajax () и set cache = false в основном сделает то же самое. jQuery добавит случайное число в строку запроса и не проверяет существующую строку запроса. Поэтому я думаю, что использования $ .get () будет достаточно.
Salamander2007
Ах, ладно. Никогда не пробовал, просто вспомнил, что видел что-то об этом в документах :)
finpingvin
Нет необходимости использовать $ .ajax. Просто используйте .ajaxSetup.
Питер J
3

Небольшое дополнение к полученным отличным ответам: Если вы работаете с решением для резервного копирования не-ajax для пользователей без javascript, вам все равно придется корректировать заголовки на стороне сервера. Это не невозможно, хотя я понимаю тех, кто бросает это;)

Я уверен, что есть еще один вопрос о SO, который даст вам полный набор заголовков, которые подходят. Я не совсем убежден, что мышиный ответ охватывает все основания на 100%

krosenvold
источник
3

Для тех из вас, кто использует cacheопцию $.ajaxSetup()на мобильном Safari, может показаться, что вам нужно использовать временную метку для POST, поскольку мобильный Safari также кеширует ее. Согласно документации $.ajax()(на которую вы направлены от $.ajaxSetup()):

Установка кеша в ложь будет корректно работать только с HEAD и GET запросами. Это работает путем добавления "_ = {timestamp}" к параметрам GET. Параметр не нужен для других типов запросов, кроме IE8, когда выполняется POST для URL, который уже был запрошен GET.

Так что установка этой опции сама по себе не поможет вам в случае, о котором я упоминал выше.

Athasach
источник
2

По сути, просто добавьте cache:false;в ajax, где вы думаете, что контент будет меняться по мере продвижения. И место, где контент не изменится, вы можете пропустить. Таким образом, вы получите новый ответ каждый раз

Сантош Упадхайай
источник
2

Ajax-кэширование в Internet Explorer: что вы собираетесь с этим делать? предлагает три подхода:

  1. Добавьте токен очистки кэша в строку запроса, например? Date = [timestamp]. В jQuery и YUI вы можете сказать им делать это автоматически.
  2. Используйте POST вместо GET
  3. Отправьте заголовок ответа HTTP, который запрещает браузерам кэшировать его.
LCJ
источник
2

Теперь это легко сделать, включив / отключив опцию кэширования в вашем запросе ajax, вот так

$(function () {
    var url = 'your url goes here';
    $('#ajaxButton').click(function (e) {
        $.ajax({
            url: url,
            data: {
                test: 'value'
            },
                cache: true, //cache enabled, false to reverse
                complete: doSomething
            });
        });
    });
    //ToDo after ajax call finishes
    function doSomething(data) {
        console.log(data);
    }
});
Омар Эль Дон
источник
3
Через 6 лет вы отвечаете так же, как Джонатан? ಠ_ಠ
redent84
люди могут сказать, что прошло 6 лет после того, как вопрос опубликован. И мой ответ на этот вопрос отличается от любого другого, не говоря уже о том, что в настоящее время он правильный. Отвечать на такие вопросы не для «спрашивающего», а для сообщества и начинающих! Спасибо за добавление разъяснения в любом случае!
Омар Эль Дон
И в чем разница между вашим и этим стеком stackoverflow.com/a/735084/469218 ?
redent84
может быть, это ясность, с точки зрения начинающего, задающего такой вопрос !!
Омар Эль Дон
1

Если вы используете IE 9, то вам нужно использовать следующее перед определением класса вашего контроллера:

[OutputCache (NoStore = true, Duration = 0, VaryByParam = "*")]

Открытый класс TestController: контроллер

Это предотвратит кеширование браузера.

Подробности по этой ссылке: http://dougwilsonsa.wordpress.com/2011/04/29/disabling-ie9-ajax-response-caching-asp-net-mvc-3-jquery/

На самом деле это решило мою проблему.

Net Solver
источник
1

Как сказал @Athasach, согласно документам jQuery, $.ajaxSetup({cache:false})он не будет работать для запросов, отличных от GET и HEAD.

Вам все Cache-Control: no-cacheравно лучше отправлять заголовок с вашего сервера. Это обеспечивает более четкое разделение проблем.

Конечно, это не будет работать для сервисных URL, которые не принадлежат вашему проекту. В этом случае вы можете рассмотреть возможность передачи сторонней службы из кода сервера, а не вызывать ее из кода клиента.

rstackhouse
источник
1

Если вы используете .net ASP MVC, отключите кэширование в действии контроллера, добавив следующий атрибут в функцию конечной точки:

[OutputCacheAttribute(VaryByParam = "*", Duration = 0, NoStore = true)]
Marius
источник
Можете ли вы объяснить это дальше? Как этот массив относится к AJAX?
Нико Хаас
Это не массив, это атрибут действия контроллера MVC.
Мариус
0

добавить заголовок

headers: {
                'Cache-Control':'no-cache'
            }
Моаз Салем
источник
Пожалуйста, добавьте некоторые объяснения к вашему ответу, чтобы другие могли извлечь из него урок - где такие заголовки должны быть добавлены?
Нико Хаас
-3

добавить Math.random() к запросу URL

xiaoyifang
источник
2
Это даст нестабильные результаты.
aj.toulan
Math.random будет действовать только как параметр, например url? _ = [Math.Random ()], он не имеет ничего общего с нестабильным результатом.
xiaoyifang
4
Я понимаю, что ты делал. Я просто комментировал, что Math.Random () иногда будет давать вам одно и то же число дважды. Если вы заполняете свою систему неопределенностями, они будут только добавляться друг на друга.
aj.toulan