Caching is not cleared for index.html

Viewed 994

We are having issues with caching in our React application.

The issue

This issue has occurred since at the start of this project because we did not include any caching headers... Our clients always have to refresh their webpage after a new production release. After that it is solved until the next release.

We would like to solve this issue so that the clients do not have to refresh the page after a new production release.

Current setup

The application is built with Create-React-App and uses the default cache-busting implementation (filename.[hash].js/css). We disabled the serviceworker by using unregister(). The application runs on Nginx built with docker.

Old Nginx config before trying to fix:

server {
  listen              443 ssl;
  ssl_certificate     /etc/nginx/ssl/server.crt;
  ssl_certificate_key /etc/nginx/ssl/server.key;

  add_header X-Frame-Options         "SAMEORIGIN";
  add_header X-Content-Type-Options  "nosniff";
  add_header Content-Security-Policy "default-src 'none'; connect-src 'self'; manifest-src 'self'; script-src 'self'; img-src 'self'; font-src 'self' https://fonts.gstatic.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; report-uri /csp/report" always;

  server_tokens off;

  root  /usr/src/app;
  index index.html index.htm;

  location ~* /favicon.ico$ {
    try_files $uri $uri/ /favicon.ico =404;
  }

  location ~* /manifest.json$ {
    try_files $uri $uri/ /manifest.json =404;
  }

  location / {
    try_files $uri $uri/ /index.html =404;
  }

  location ~ .(static)/(js|css|media)/(.+)$ {
    try_files $uri $uri/ /$1/$2/$3 =404;
  }
}

Things we have tried:

We tried to change the headers for the index.html in Nginx:

  location / {
    try_files $uri $uri/ /index.html =404;

    add_header Cache-Control "no-cache, no-store, no-transform, must-revalidate, max-age=0";
    add_header Pragma "no-cache";
    add_header Expires "0";
  }

We expected this to fix the caching issue that we were having for the index.html. When we open the application in Chrome, it opens the old version. When we then press F5, Chrome loads the new version with the Cache-Control headers. Then we open a new tab in Chrome and it shows the old version of the application again.

Something that worked (but only for browsers that support it) is by adding the Clear-Site-Data header. This tells us at least that it is a caching problem.

  location / {
    try_files $uri $uri/ /index.html =404;

    add_header Clear-Site-Data "\"cache\"";
  }

These are the headers that we are getting back from Nginx after loading the new version of the application with Cache-Control headers (after pressing F5).

HTTP/1.1 200 OK
Server: nginx
Date: Fri, 17 Dec 2021 08:51:33 GMT
Content-Type: text/html
Content-Length: 1113
Last-Modified: Thu, 16 Dec 2021 14:35:26 GMT
Connection: keep-alive
ETag: "61bb4eae-459"
Cache-Control: no-cache, no-store, no-transform, must-revalidate, max-age=0
Pragma: no-cache
Expires: 0
Accept-Ranges: bytes
Strict-Transport-Security: max-age=31536000

Why is Chrome still loading the old web application even though we loaded the application using these new caching headers?

Thanks in advance for your advice / help.

1 Answers

A bug in Chrome 91 incorrectly shows 304 server responses as 200 in DevTools. Check your Nginx server log to ensure the correct responses are being sent. I had to explicitly set if_modified_since off to prevent the 304 responses to Chrome. Use a new Incognito Chrome tab during testing to prevent the browser from re-using cached pages.

server {
  location /no-cache-test {
    add_header Cache-Control no-cache;
    etag off;
    if_modified_since off;
  }
  ...
}
$ mkdir no-cache-test
$ touch no-cache-test/index.html
$ curl -I https://example.com/no-cache-test/

HTTP/2 200 
server: nginx
date: Fri, 17 Dec 2021 17:11:54 GMT
content-type: text/html; charset=utf-8
content-length: 0
last-modified: Fri, 17 Dec 2021 16:53:14 GMT
cache-control: no-cache
accept-ranges: bytes
$ sudo tail -f /var/log/nginx/example.com.access.log

[17/Dec/2021:12:12:47 -0500] "GET /no-cache-test/ HTTP/2.0" 200 0 "-"
Related