Django routing with VueJS single page has unexpected behaviour when there is no trailing slash in the URL
Django routing with VueJS single page has unexpected behaviour when there is no trailing slash in the URL
--
Become part of the top 3% of the developers by applying to Toptal
https://topt.al/25cXVn
Music by Eric Matyas
https://www.soundimage.org
Track title: Secret Catacombs
Full question
https://stackoverflow.com/questions/5897...
Question links:
[this]: https://stackoverflow.com/questions/4286...
Accepted answer links:
[Temporary Redirect 307]: https://developer.mozilla.org/en-US/docs...
--
Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...
--
Chapters
00:00 Question
02:42 Accepted answer
05:13 Thank you
--
Tags
#python #django #vue.js #routing #trailingslash
ACCEPTED ANSWER
Score 0
The problem is that you have a catch-all in re_path(r'^.*$', views.vue), so if any URL is not matched exactly on the earlier paths, this will be triggered.
Django's CommonMiddleware actually appends a trailing slash and redirect, when it finds a 404 and the URL path does not end in / (depending on the APPEND_SLASH setting), but that's on response.
In you case, you can have a tiny request middleware that appends trailing slash if the request path not end in / e.g.:
from django.shortcuts import redirect
class AppendTrailingSlashOnRequestMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not request.path.endswith('/'):
query_string = request.META['QUERY_STRING']
query_string = f'?{query_string}' if query_string else ''
to_url = f'{request.path}/{query_string}'
return redirect(to_url, permanent=True)
response = self.get_response(request)
return response
Add the middleware to settings.MIDDLEWARE obviously, preferably put it at the top to prevent unnecessarily processing from other middlewares as we'll be redirecting anyways and processing would be required then as well.
But this has an issue; the data from POST/PUT/PATCH will be lost when doing redirection (here we're doing 301 but similarly applicable for 302. There's Temporary Redirect 307 that can help us in this regard and the good thing is all the regular browsers including IE support this. But Django does not have this out of the box; so we need to implement this ourselves:
from django.http.response import HttpResponseRedirectBase
class HttpTemporaryResponseRedirect(HttpResponseRedirectBase):
status_code = 307
Now, import that in the middleware, and use it instead of redirect:
class AppendTrailingSlashOnRequestMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not request.path.endswith('/'):
query_string = request.META['QUERY_STRING']
query_string = f'?{query_string}' if query_string else ''
to_url = f'{request.path}/{query_string}'
return HttpTemporaryResponseRedirect(to_url) # here
response = self.get_response(request)
return response
N.B: If you want to keep the browser caching facilities for GET, you can redirect to 301/307 based on request.method.