53

I am trying to query a quote API for a freeCodeCamp project I'm updating to React.js. I am now trying to use Fetch or Axios to query the API but it's caching the response in the browser. I know in $ajax there is a { cache: false } that would force the browser to do a new request.

Is there some way I will be able to do the same with Fetch or Axios?

The cache-control setting seems to be already set to max-age: 0 by Axios.

enter image description here

This is my code I have that is querying the API.

generateQuote = () => {
  axios.get('https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1')
    .then(response => {
      const { title, content, link } = response.data[0];
      console.log(title, content, link)
      this.setState(() => ({ title, content, link }));
    })
    .catch(err => {
      console.log(`${err} whilst contacting the quote API.`)
    })

}

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Asjas
  • 1,362
  • 1
  • 11
  • 16
  • 8
    Have you tried `'Cache-Control': 'no-cache'` in axios settings? – Prasun Mar 13 '18 at 18:47
  • 1
    Yup. That specific API starts giving a error about no `Cache-Control` found pre-flight. It seems I can't set that header like that with that specific API – Asjas Mar 13 '18 at 19:34

6 Answers6

67

Okay so I found a solution. I had to set a timestamp on the API url to get it to make a new call. There doesn't seem to be a way to force axios or fetch to disable cache.

This is how my code now looks

axios.get(`https://quotesondesign.com/wp-json/posts?filter[orderby]=rand&filter[posts_per_page]=1&timestamp=${new Date().getTime()}`)
  .then(response => {
    const { title, content, link } = response.data[0];
    console.log(title, content, link)
    this.setState(() => ({ title, content, link }));
  })
  .catch(err => {
    console.log(`${err} whilst contacting the quote API.`)
  })
Asjas
  • 1,362
  • 1
  • 11
  • 16
  • 13
    With axios 0.18.0 the request was always sent if the _response_ had the `Cache-Control: no-cache` header set. – pma Oct 24 '18 at 10:21
  • 1
    This was happening for me on IE 11 (using Outlook Addin). This solution worked like a charm. – TheScrappyDev Jul 16 '19 at 22:24
  • 2
    This worked for me. I added a timestamp param to all get requests from the request interceptor and it didn't seem to cause any issues with anything else. Thanks. – HartleySan May 30 '20 at 11:47
  • 2
    adding timestamp in request url is treated as another new url. Does axios store this data as cache for each url? – Santosh Karanam Aug 13 '21 at 09:18
  • 2
    Adding an additional parameter may not be always possible, the API could refuse to answer... Also this solution is not 100% guaranteed to always use a different timestamp value (race conditions), maybe also add a random value to the URL additionally – m13r Mar 10 '22 at 15:16
43

I added these headers to all axios requests and it's working well.

axiosInstance.defaults.headers = {
  'Cache-Control': 'no-cache',
  'Pragma': 'no-cache',
  'Expires': '0',
};
Greg T
  • 3,278
  • 3
  • 37
  • 39
  • The `Pragma: no-cache` is required for iOS Safari to behave correctly, see https://bugs.webkit.org/show_bug.cgi?id=170714 – diachedelic Oct 20 '20 at 03:49
  • 12
    This results in an error with this message: `Request header field cache-control is not allowed by Access-Control-Allow-Headers in preflight response.` – therealak12 Dec 20 '20 at 09:19
18

If you do not want to disable caching for all axios requests, you can disable caching for only one request by using the following parameters in the axios call:

axios.get(
  'https://YOUR-URL.com',
  {
    // query URL without using browser cache
    headers: {
      'Cache-Control': 'no-cache',
      'Pragma': 'no-cache',
      'Expires': '0',
    },
  }
)
m13r
  • 2,458
  • 2
  • 29
  • 39
  • It's the same answer as this? https://stackoverflow.com/a/62781874/8294418 – Asjas Sep 27 '21 at 15:40
  • 1
    No, the answer you`ve linked sets it for *all* axios requests, but this is may not be always wanted. The OP asks for an equivalent like in ajax... I will change my answer description to explain more.. – m13r Sep 27 '21 at 19:25
  • 4
    This was helpful, I only need to do a cache-less fetch occasionally - was nice to see how to add the headers in on a per-call basis without touching the main axios config – sirclesam Jan 19 '22 at 00:26
  • 1
    Axios still cache previous errors and block requests/not going to request again. But after adding that's the line, it works. Thanks! – Bcktr May 17 '22 at 07:26
  • this is never reliable. I have seen so many proxies and routers and firewall ignoring all the headers and continuing responding with cached data. the only reliable method is a random number in query string – Nir O. Dec 18 '22 at 19:59
4

It seems, adding timestamp is the only always working way.

If you're using Vue, for example:

const api = axios.create({
  baseURL: 'https://example.com/api',
  params: {
    t: new Date().getTime()
  }
})
Vue.prototype.$api = api

So you can use it with:

this.$api.get('items')

And it will always add different timestamp to the url, depending on current request time.

Anar Salimkhanov
  • 729
  • 10
  • 12
3

I think you just need to make the url different each time you make the axios call. Timestamp is just one way to do so. Also consider disabling or filtering service workers caching method if you are developing a PWA.

Al Herrera
  • 165
  • 5
  • 1
    If you check the screenshot you will see there is no service worker file being downloaded, because I wasn't using a service worker to create a PWA. – Asjas Feb 25 '19 at 07:30
  • 1
    Al Herrera, does adding the timestamp also prevent a service worker from catching? – Xeverus Nov 22 '19 at 02:36
3

Create an instance of axios and then add timestamp to every request.

const axiosInstance = axios.create({})

axiosInstance.interceptors.request.use(
    function (config) {
      // Do something before request is sent
      config.params = { ...config.params, timestamp: Date.now() };
      return config;
    },
    function (error) {
      // Do something with request error
      return Promise.reject(error);
    }
  );
Milad Raeisi
  • 459
  • 5
  • 9