This reminded me of [https://twitter.com/simonw/status/1047865898717966337
this Tweet by Simon Willison] about accelerating redirects using a HTTP/2
Server Push header. I did some further research and stumbled upon
[https://www.ctrl.blog/entry/http2-push-redirects 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.
--
Ticket URL: <https://code.djangoproject.com/ticket/29925>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
Comment (by Claude Paroz):
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.
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:1>
Comment (by Jaap Roes):
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
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:2>
* stage: Unreviewed => Accepted
Comment:
Nice! I guess the next step is to prepare a patch for Django.
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:3>
Comment (by Jaap Roes):
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:
{{{#!python
from django.utils.http import is_safe_url
class Http2ServerPushRedirectMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
response = self.get_response(request)
if request.is_secure and response.status_code in {301, 302} and
hasattr(response, 'url'):
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 [https://github.com/leukeleu/django-push-redirect 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.
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:4>
* status: new => closed
* resolution: => wontfix
Comment:
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.
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:5>
Comment (by Jaap Roes):
I finally got around to packaging this up and releasing it to PyPI
https://pypi.org/project/django-push-redirect/
--
Ticket URL: <https://code.djangoproject.com/ticket/29925#comment:6>