I have a production set up as follows;
- Django REST Framework backend
- Vuejs frontend
- Docker container that builds Vuejs for production and copies to Django Docker container /static/ and /template/ folders
- nginx reverse proxy to handle incoming requests
Everything works fine when I navigate to home page (no backend API calls on homepage) and then navigate around the SPA using the navigation drawer.
I start to get problems when I try to go directly to a Page in the SPA. The backend requests that should fire on "create" in Vuejs are not firing.
I have seen some people suggest this is related to Vue router being in history mode, which I would like to keep.
The main suggested remedy is to add try_files $uri $uri/ /index.html; as a catch all to the nginx config. However, as I am simply proxying all requests to Django to handle the initial stage of routing, and I already have a catch all in my urls.py file (re_path(r"^.*/$", TemplateView.as_view(template_name="index.html"), name="frontend")) then I think I have this covered.
Why would the API requests (which are fired on create of Vuejs page) work when navigating using the router, but not when navigating directly to the Page by URL?
nginx config
server {
listen 80;
location / {
proxy_pass http://csgs:8000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# try_files $uri $uri/ /index.html;
}
location /static/ {
alias /home/app/web/static/;
}
}
django urls.py patterns
urlpatterns = [
path("admin/", admin.site.urls),
path("api-auth/", include("rest_framework.urls")),
path("api/", include("api.urls")),
path("", TemplateView.as_view(template_name="index.html"), name="home"),
re_path(
r"^.*/$", TemplateView.as_view(template_name="index.html"), name="frontend"
),
]
SPA index page body:
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
Update: I've put debug statements in and can now compare the request sent and response received in each scenario.
Vue router navigation:
url = api/booking/ground-stations/ user.service.js:11:16
request = {
"params": null,
"headers": {
"Authorization": "Token 164d5d7bc0fc0be90168739958c0c8640ed52f60"
}
}
response = {
"data": [
{}
],
"status": 200,
"statusText": "OK",
"headers": {
"allow": "GET, HEAD, OPTIONS",
"connection": "keep-alive",
"content-length": "82",
"content-type": "application/json",
"date": "Sat, 10 Oct 2020 21:49:58 GMT",
"referrer-policy": "same-origin",
"server": "nginx/1.17.10",
"vary": "Accept",
"x-content-type-options": "nosniff",
"x-frame-options": "DENY"
},
"config": {
"url": "api/booking/ground-stations/",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": "Token 164d5d7bc0fc0be90168739958c0c8640ed52f60"
},
"params": null,
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
},
"request": {}
}
Browser refresh:
url = api/booking/ground-stations/ user.service.js:11:16
request = {
"params": null,
"headers": {
"Authorization": "Token 164d5d7bc0fc0be90168739958c0c8640ed52f60"
}
}
response = {
"data": "<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content=\"IE=edge\"><meta name=viewport content=\"width=device-width,initial-scale=1\"><link rel=icon href=/static/favicon.ico><title>CS: GS</title><link rel=stylesheet href=\"https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900\"><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css><link rel=stylesheet href=https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css><link href=\"https://fonts.googleapis.com/css2?family=Orbitron:wght@400;800&display=swap\" rel=stylesheet><link href=/static/css/app.d8cde755.css rel=preload as=style><link href=/static/css/chunk-vendors.93ac251e.css rel=preload as=style><link href=/static/js/app.7e344e2e.js rel=preload as=script><link href=/static/js/chunk-vendors.945fac67.js rel=preload as=script><link href=/static/css/chunk-vendors.93ac251e.css rel=stylesheet><link href=/static/css/app.d8cde755.css rel=stylesheet></head><body><noscript><strong>We're sorry but frontend doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/static/js/chunk-vendors.945fac67.js></script><script src=/static/js/app.7e344e2e.js></script></body></html>",
"status": 200,
"statusText": "OK",
"headers": {
"connection": "keep-alive",
"content-length": "1315",
"content-type": "text/html; charset=utf-8",
"date": "Sat, 10 Oct 2020 21:51:25 GMT",
"referrer-policy": "same-origin",
"server": "nginx/1.17.10",
"x-content-type-options": "nosniff",
"x-frame-options": "DENY"
},
"config": {
"url": "api/booking/ground-stations/",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*",
"Authorization": "Token 164d5d7bc0fc0be90168739958c0c8640ed52f60"
},
"params": null,
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1,
"maxBodyLength": -1
},
"request": {...}
}
So my question now becomes; why does refreshing the page result in an html response to my backend API queries when the url and request remain the same for both vuejs router and firefox browser navigation?
UPDATE 2: So did some more investigating. First I removed the catch all statement in Django urls and replaced with explicit statements;
path("", TemplateView.as_view(template_name="index.html"), name="home"),
path("ground-stations/", TemplateView.as_view(template_name="index.html"), name="gs"),
Now I should see when any 404s occur.
Now when I send a request I can see that when navigating using the Vuejs API axios appends the endpoints to the base url "http://127.0.0.1:7100/", which is correct. However, if I refresh the page the base url now becomes "http://127.0.0.1/ground-stations/", and the endpoints are appended onto this, which is incorrect.
Why is this happening and how do I fix it?