#29925 closed New feature (wontfix)
Redirect with HTTP/2 Server Push
Reported by: | Jaap Roes | Owned by: | nobody |
---|---|---|---|
Component: | HTTP handling | Version: | dev |
Severity: | Normal | Keywords: | http2 server push redirects |
Cc: | Triage Stage: | Accepted | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
I was looking into upgrading nginx and reading it's changelog when I noticed HTTP/2 Server Push support was introduced semi-recently.
This reminded me of this Tweet by Simon Willison about accelerating redirects using a HTTP/2 Server Push header. I did some further research and stumbled upon this article about the same concept.
This got me thinking about using this technique in Django.
There are a few places in Django's code base that will perform redirects to "better" urls, e.g. when using CommonMiddleware
and APPEND_SLASH is True
and/or PREPEND_WWW is True
or using LocaleMiddleware
i.c.w. i18n_patterns
. Wouldn't it be nice if these redirects also included a Link: <redirect-location>; rel=preload
header?
Would adding something like this be acceptable to the Django codebase? I'm unsure if it's safe to include this header on non-http/2 connections/servers, but I'd assume it will be.
A step further would be to always do this for all HttpResponseRedirectBase
classes, or alternatively, introduce a Http2ServerPushRedirectBase
class.
Change History (6)
comment:1 by , 6 years ago
comment:2 by , 6 years ago
No, I did not experiment with this at all and was just basing all of this on the Tweet and article I mentioned in the ticket. Sadly none of our production servers have a recent enough nginx version, so I cannot do any "real world" tests.
However, I did create a small docker-compose
project that sets up nginx and a Django project with a custom redirect class and a patched CommonMiddleware
. It seems to work pretty nice. You can check it out here: https://github.com/leukeleu/django-push-redirect
comment:3 by , 6 years ago
Triage Stage: | Unreviewed → Accepted |
---|
Nice! I guess the next step is to prepare a patch for Django.
comment:4 by , 6 years ago
After contemplating for a while on how to implement this nicely, I came to the conclusion that the easiest/neatest way to do this would be to just introduce a new middleware:
from django.utils.http import is_safe_url class Http2ServerPushRedirectMiddleware: redirect_status_codes = {301, 302} def __init__(self, get_response): self.get_response = get_response def should_preload(self, request, response): return ( request.is_secure and response.status_code in self.redirect_status_codes and hasattr(response, 'url') and not response.has_header('Link') ) def __call__(self, request): response = self.get_response(request) if self.should_preload(request, response): url = response.url if is_safe_url(url, allowed_hosts={request.get_host()}, require_https=True): response['Link'] = f'<{url}>; rel=preload' return response
This works as long as this middleware is placed before CommonMiddleware
.
I've updated the test project to use this approach as well.
Are you still interested in having a middleware like this in Django core? Releasing this as a 3rd party package could be a sufficient solution as well.
comment:5 by , 6 years ago
Resolution: | → wontfix |
---|---|
Status: | new → closed |
Yes, in that case I guess having a 3rd-party app might be the way to go.
A request to integrate it into Django may come later when the app is well-tested and HTTP/2 usage is a bit higher.
comment:6 by , 5 years ago
I finally got around to packaging this up and releasing it to PyPI https://pypi.org/project/django-push-redirect/
Interesting. Did you experiment such a configuration in a real project successfully? In that case, I don't currently see what would prevent implementing this optimization in Django.