【发布时间】:2021-01-25 13:04:58
【问题描述】:
我的生产设置如下;
- Django REST 框架后端
- Vuejs 前端
- 为生产构建 Vuejs 并复制到 Django Docker 容器 /static/ 和 /template/ 文件夹的 Docker 容器
- nginx 反向代理处理传入请求
当我导航到主页(主页上没有后端 API 调用)然后使用导航抽屉在 SPA 中导航时,一切正常。
当我尝试直接转到 SPA 中的页面时,我开始遇到问题。应该在 Vuejs 中“创建”时触发的后端请求没有触发。
我看到有人认为这与 Vue 路由器处于历史模式有关,我想保留它。
建议的主要补救措施是将try_files $uri $uri/ /index.html; 作为全部添加到 nginx 配置中。但是,由于我只是将所有请求代理到 Django 以处理路由的初始阶段,并且我的 urls.py 文件 (re_path(r"^.*/$", TemplateView.as_view(template_name="index.html"), name="frontend")) 中已经包含了全部内容,因此我想我已经涵盖了这一点。
为什么 API 请求(在创建 Vuejs 页面时触发)在使用路由器导航时有效,但在通过 URL 直接导航到页面时无效?
nginx 配置
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 模式
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 索引页面正文:
<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>
更新: 我已经放入了调试语句,现在可以比较每个场景中发送的请求和收到的响应。
Vue 路由器导航:
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": {}
}
浏览器刷新:
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": {...}
}
所以我的问题现在变成了;当 vuejs 路由器和 firefox 浏览器导航的 url 和请求保持不变时,为什么刷新页面会导致对我的后端 API 查询的 html 响应?
更新 2: 所以做了一些更多的调查。首先,我删除了 Django url 中的 catch all 语句并替换为显式语句;
path("", TemplateView.as_view(template_name="index.html"), name="home"),
path("ground-stations/", TemplateView.as_view(template_name="index.html"), name="gs"),
现在我应该看看何时发生任何 404。
现在,当我发送请求时,我可以看到在使用 Vuejs API 进行导航时,axios 会将端点附加到基本 URL“http://127.0.0.1:7100/”,这是正确的。但是,如果我刷新页面,则基本 url 现在变为“http://127.0.0.1/ground-stations/”,并且端点会附加到此页面上,这是不正确的。
为什么会发生这种情况,我该如何解决?
【问题讨论】: