I have a Django app served on EC2, and Cloudflare sits in front of the app to cache the static content (JS and CSS files; images are hosted separately on S3 and served via Cloudfront again with Cloudflare on top).
Every time I deploy new CSS, the hash in the filename of my CSS file changes, e.g. my_stylesheet.12345678.css
.
Occasionally, after a release that involved a CSS change, I get some users emailing me that the website renders as "just text". Investigation led to find that the page in their browser has HTML that points to a previous release of the CSS file, e.g. my_stylesheet.11111111.css
, which doesn't exist on my webserver anymore.
Since my website is very dynamic (it's a social network, so most pages will change at every request due to new posts, new comments, new likes, etc), to address this issue I have removed all client-side caching: I now send this header with pages like the main page:
cache-control: no-cache, no-store, must-revalidate, max-age=0
.
I achieve this with Django's @never_cache
decorator.
These are my Cloudflare page rules:
And these are the request/response header for the main page when I request it:
Request URL: https://www.example.com/
Request Method: GET
Status Code: 200
Remote Address: 111.111.111.111:443
Referrer Policy: strict-origin-when-cross-origin
cache-control: no-cache, no-store, must-revalidate, max-age=0
cf-cache-status: DYNAMIC
cf-ray: 63b9a4726dbe0e26-MXP
cf-request-id: 0947e51b7f00000e2661a28000000001
content-encoding: br
content-language: en
content-type: text/html; charset=utf-8
date: Tue, 06 Apr 2021 08:28:23 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: Tue, 06 Apr 2021 08:28:23 GMT
nel: {"max_age":604800,"report_to":"cf-nel"}
report-to: {"max_age":604800,"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report?s=YSpdY1LGNVOgbemDSBUL5DCg%2FDAX9NY3iGwLfpGvdQDQW9bxtzHIsNUxWFzei98JPs3IM2B4M%2FfepaN2CmIRH90HeUwOlYvCyNz%2Btd3iWavI"}],"group":"cf-nel"}
server: cloudflare
set-cookie: AWSALB=JcZVQeHr1BkaITzKti5bhIEeq9J9qZTufpjPTIvZukaeWLIEjlsOn75fFZXCIyMWN1F/NIYX2c7PsddmxAGNCSKp5EJxiZ59AKVTyOgVAfH89pqUPfX++uC3OUfF; Expires=Tue, 13 Apr 2021 08:28:22 GMT; Path=/
set-cookie: AWSALBCORS=JcZVQeHr1BkaITzKti5bhIEeq9J9qZTufpjPTIvZukaeWLIEjlsOn75fFZXCIyMWN1F/NIYX2c7PsddmxAGNCSKp5EJxiZ59AKVTyOgVAfH89pqUPfX++uC3OUfF; Expires=Tue, 13 Apr 2021 08:28:22 GMT; Path=/; SameSite=None; Secure
set-cookie: csrftoken=oUjzFDSxELNFfgtfNjqxIEkufxlyPaVaFXqsu7wK4jbK7xN1Z2ZQr5z0oDo9AYKO; expires=Tue, 05-Apr-2022 08:28:23 GMT; Max-Age=31449600; Path=/
set-cookie: sessionid=".eJyFWE1vG0cM_SuBz_Vg-DVfp8K596S7sJJWsRpZTrVS2iLIfy9Har2zq4ILGL6sOOSQ75GP8-NpfzgPl_X1dO673Xr_fl5f3r8dtmvwOfqn8oQe4dnTM-IKUpFUmJ1-YoxPv1i21NrKylMhX5hcDBgi2LY884uFU0F2zAGQbNvQ2vIKoXgpnF2MEdOCbWptaQW5QCwcnAacAtq2ubElWKHGDEWCo5SIxLAF73H97X24PBWSnIPlJbVeMK6ANS0FvEOUwHZWQ_rwErI3vcjMixQtPaFTF0DZ9JJ4VndNgqYxOS27eDvCFKZ-1VbTCOQoQAWUaQvTulesxkLsMIeMyc6__y8zQQ8wvcxQDb5gKj66CIEz2xHi7HZKh1CIXK4IWcgMfdQuIZtVnngJK6guCgaHlIO3axdiawsVXZyLeAdad7QwrLZhylmk4nPlDoJkqtw5dd_X28tf-rPr0J-twxI2hMBkus3TkNUtQaHkJIUgVtkrIaa2vt61wg1JYW7DLYcxwljJdDxsv9bvX_vT_b-eHfXuMQKHKOyV2vF504W4Zc6y2cnGd7WFnvs_rr16mRnFKDFFLQk8x-2eCYlS7pOk3S2wB3frmtT1aTjs9AwOrCeA__U3byOf5AP5KDw7t9tu-2FYH_vv_VEPrdZmTih-5CSy0mj3e3f68r4-6v9r96XXIw6Xhd4xohzMPhjHXhYDWTfEj0IFSNnm5-g9avjr7np5vad10201ITWz3XA5v28OJ1c_us_X4fL-9vLvV-twkYfR4rWl1rGU0G5tlGW8rEd76DZtwmzxMNYqhWglEMaGwhr8CpUiUBtKIkS7bQWMrS1XWxUBys7EzAstL8PIMJqW47UbXvVg2FASvyHZxbDdeYxd2Kad0qon2vq4Y9hsYxdtnZJz40bMKTEmN9-Q1HJlfz0eT91bBfnn1-587IdPL-duN7x2fy50uhYXeeVjEb5LDu0xXm2H69tbd_57vT8cL_15eCo_fppR8jjLLGZo-5PmPgYEahkbDpkAZJmqIJ0gKh48OT0lBXuCxDxG7o2mr3eMj5BElaYuYea4MOtDa3uLUCc4RycMSRZ02ux29xnng9PuHtnbttz6vWna-6BKOXCyqFCRN8uqXlaqLSnLeUlbPlQEQxF0GDyRpWnVttVU5G_glILggETY0hJVU03zrLZMVf8rZUkW1M6IzJRMTiKMyASzu4emu4v5yzhOoYgyG9Drod-ee_34RKHb61ymDjDC3u8XkNNg255CY9tL3uQvxZnium9JpFsSJVhQy6GZdfS_euLjorzBxEk6LVsOu009uOnFd71hiwxqoRBWOvh0rdJ1QiIx2bShCYykUl0UvuxAFWdaEjePfvlGGx0oJvR1LKRmLFiTNEwbihI73hY_r7cDbZcLgrtZyUwZ40OzopiUoHGZQbTaekaYAUjDptoKM2jB7daAMp3s_nZrFp1bwZuLqNrOVUHt3YWi89Gr6rVtwxQP6lcTrq2fKPu4EDNMx4ZOJsWSEkYCxYUVHf3DyMFcY1amBbMFK5Z8o7WM8ale8gPa9c-DE9Al1mYKpgdbHTBYH1yEiMdNo9-tv_Xnt8MwHN5Pw6Kwz-LTDOGiha5RoUpXc6hX7jcLht3KR9yCLcQwNQg3fllV7nQZVoTrQqvrevIpLmyH2U9t749B5PXW4mNY0K5TVaeCub5hqdonf1d11mY5Hbp1o6Xbo5uA7rQLj1_N8DDHTJZphPWdRW8HjlMMCxIKc5N_8zEip8c8QBUfVEFpP5fkPLO95QHEcVX9C49QuREQCyJ4Jo-gPsqIMi4KJbNSyTc7lJiyuNngVKDavbGR2kZu617W8MVegUfxAWy-pkizaVqdqt59yo761oPFi_ZSZYefP1FUqdCuR4f-0wt6MPJb28448qL5GjCqwCrDTYKMrVi1h_2wNP4SzDNDaLxb7YimpIPbG6XmDXRvUSFkUbvuPE25rchDKxWyOW5AHqSLLp9ETvevFGwFyQ2ks703N4u8RZMaTxM5__wHd3-R6w:1lTh4R:vHTnt7OdEA38hHpwyLYi3Ir0Vyg"; expires=Sun, 03-Oct-2021 08:28:23 GMT; httponly; Max-Age=15552000; Path=/
vary: Accept-Encoding, Accept-Language, Cookie
X-DNS-Prefetch-Control: off
:authority: www.example.com
:method: GET
:path: /
:scheme: https
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
accept-encoding: gzip, deflate, br
accept-language: en-US,en-GB;q=0.9,en;q=0.8,it;q=0.7
cache-control: max-age=0
cookie: (redacted)
sec-ch-ua: "Google Chrome";v="89", "Chromium";v="89", ";Not A Brand";v="99"
sec-ch-ua-mobile: ?0
sec-fetch-dest: document
sec-fetch-mode: navigate
sec-fetch-site: same-origin
sec-fetch-user: ?1
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
The issue is not specific to a browser, because I've had people report it about Chrome, people reporting about Firefox, people reporting about Safari.
One user had the same issue across all his browsers in his network, across multiple devices.
What could be causing this? How can I fix it?
Please let me know if you need more information to help me.
Thank you!
Changes to caching are not retroactive, meaning that if your users visited your website before you made the changes to the cache headers then the old cache control header would still be in effect.
In order to fix this, hope that your initial cache headers were setup to expire or refresh soon, otherwise users will need to manually clear their cache.
This also applies to proxies outside of your control that may have possibly cached your web page as well. Proxies inside your control should be purgeable.
Since you are using hashes in the filenames for resources you can leave the old files in place when you release a new version. This way your website won't break for users who still have old versions cached which refer to old versions of resources.
In order to have the latest version of the website load for users when they refresh the page, we use the following cache control for all index/html pages:
Cache-Control: public, must-revalidate, proxy-revalidate, max-age=0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With