Opened 3 years ago

Closed 3 years ago

Last modified 15 months ago

#32891 closed Bug (wontfix)

runserver serve static files cached in debug

Reported by: TZanke Owned by: TZanke
Component: contrib.staticfiles Version: 3.2
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: yes UI/UX: no

Description

Hello,

right now i experience a problem with runserver and serving static files.

1) open chrome
2) open F12 debug tools
2) start runserver (Debug True)
3) open django site with a js/css required in head
4) have a look at a js/css file in network tab of debugger. At first the css/js file is loaded with status code 200, on F5 press maybe chrome just checks again an gets a 304. Fine. But sometime (at least 80% of the time) chrome does not check the server file again. I dont know why chrome does not refreshes the file every time when 'just' F5 is pressed. CTRL+F5 will fix the issue, but i think runserver with Debug=True should care about this problem itself to allow fast and easy development of js/css.

Possible fix: Add add_never_cache_headers to the static.py serve method

Right now i am not able to check the problem and fix on the latest version of Django, is there any simple way to setup a Django Environment with master branch to revalidate this issue?

Merge request on github: https://github.com/django/django/pull/14571

Right now i am not aware of all your django related requirements for submitting a code change / pull request / commit message / tests so please be gentle and take my pull request just as a possible example how to fix the issue. I know there is a lot more work to do.

Best regards
Tobias

Change History (10)

comment:1 by Wu Haotian, 3 years ago

Owner: changed from nobody to TZanke
Status: newassigned

comment:2 by Carlton Gibson, 3 years ago

Resolution: wontfix
Status: assignedclosed

Hi Tobias — Welcome aboard!

Possible fix: Add add_never_cache_headers to the static.py serve method

I don't think this is the right approach. As far as I can see the browser behaviour is correct and as desired, serving static assets from the browser cache when possible.

When working on a file this behaviour can be undesired. For that all the browsers allow disabling the caches (at least while the dev tools are open) by accessing the settings (normally via the little cog or hamburger menu on in the dev tools, or via the Develop menu in Safari). If you check this static assets are fetched on each request.

If you really wanted to add no cache headers you could do so in a middleware, but I don't think it's appropriate for projects in general.

I hope that makes sense.

in reply to:  2 comment:3 by TZanke, 3 years ago

Hello Carlton,

my (and my coworkers) expected behavior, with DEBUG=True, was a non-cached js/css file. So while developing, new colleges always struggle debugging, cause "my files does not get refreshed, but debug is on! Help me!". Yeah no problem, we always use the "disable browser cache" but maybe we are not alone with this problem, and this could easily be fixed. Cause static.py serve only is used in Debug mode by Django.

But we will respect the decision made.

If you really wanted to add no cache headers you could do so in a middleware, but I don't think it's appropriate for projects in general.

I've tried, but its not working. static.py serve is called within the 'StaticFilesHandler', skipping the Middlewares from BaseHandler.
See: https://github.com/django/django/blob/main/django/contrib/staticfiles/handlers.py#L53
No super call, no Middleware execution.

But keep in mind, i am not able to test with a new Django version right now. Maybe i am wrong 'just lookin at github'. But in Django 1.11 Middlewares are skipped.
(And yees, we are are nearly finished with Python3 conversion, so Django 2/3 is coming...soon ;)

Best regards
Tobias

comment:4 by Carlton Gibson, 3 years ago

Hi Tobias.

... is called within the 'StaticFilesHandler'...

Yes, of course. (Doh.)

In that case using the browser dev tools to disable caching is the way to go.
Thanks.

comment:5 by Dan Swain, 3 years ago

Resolution: wontfix
Status: closednew

I would like to revisit this issue and make a distinction between static assets held by the Django site vs CDN-delivered content. Using the Disable cache option in the Network tab of developer tools DOES accomplish reloading static assets, BUT it causes ALL static assets to be reloaded including CDN-delivered content. I like to set up libraries to be delivered via CDN, even in development mode. Therefore, I would like to see runserver deliver new versions of ONLY the static assets that are housed in the Django project but NOT the CDN-delivered content. This behavior would allow development to continue even if an Internet connection is interrupted since CDN-delivered content would always be pulled from the cache. If this behavior is not the desired default for runserver (though I can't see why it wouldn't be), then perhaps a flag such as --always-refresh-static would be in order to trigger this behavior.

Finally, I know that I could use a bundler such as Vite or Snowpack to do hot reloading of static files, but I'm not currently using a bundler and so would like to see the above-described behavior included with runserver.

comment:6 by Mariusz Felisiak, 3 years ago

Resolution: wontfix
Status: newclosed

I appreciate you'd like to reopen the ticket, but please follow the triaging guidelines with regards to wontfix tickets and take this to DevelopersMailingList.

comment:7 by Ole Laursen, 3 years ago

I just ran into this ticket - I have the reverse problem, I'd like the static serve to send out a cache forever header, since I have a cache buster in place (it appends ?_=[timestamp of file] to all references to static assets). So it would be nice if I could get rid of the HTTP spam from the 304s.

Perhaps a compromise could be a relatively easy way of setting the static cache headers? Like:

    re_path(r'^static/(?P<path>.*)$', django.views.static.serve, {'document_root': settings.STATIC_ROOT, 'cache_control': {'no_store':True, 'max_age': 0}}),

I'm currently using a wrapper like this:

def static_serve_with_forever_cache(request, *args, **kwargs):
    response = django.views.static.serve(request, *args, **kwargs)
    if '_' in request.GET:
        patch_cache_control(response, public=True, max_age=365 * 24 * 60 * 60, immutable=True)
    return response

So it's not a big deal. But it is somewhat of a foot gun, so explicit support with a little note in the documentation might be useful?

comment:8 by Mariusz Felisiak, 3 years ago

#33148 was marked as a duplicate of this ticket.

comment:9 by Carlton Gibson, 15 months ago

Same topic was also in #27572. There's a simple wrapper for static.serve in https://code.djangoproject.com/ticket/27572#comment:4

comment:10 by Kevin Christopher Henry, 15 months ago

This issue is being discussed in the Django Forum.

Note: See TracTickets for help on using tickets.
Back to Top