在 vue + django webpack 应用程序中处理页面

Posted

技术标签:

【中文标题】在 vue + django webpack 应用程序中处理页面【英文标题】:Handling pages in a vue + django webpack application 【发布时间】:2021-06-09 23:31:16 【问题描述】:

我将 Vue 添加到我的 Django 项目中,但由于我不想将前端与后端分离,我决定直接从 Django 加载 webpack。我的设置似乎适用于 django webpack loader,但我对我如何构建项目有一些疑问。

这是我的文件夹:

my_site
   - django settings
my_app
   - views, urls, models, templates
vue_frontend 
   - webpack and vue stuff

我的疑问是:路由应该由 Django 处理还是应该由 SPA 中的 Vue 处理?

这是我现在拥有的:

django_template2.html

% extends 'header.html' %
% load render_bundle from webpack_loader %
% block content %

<body>
    <div id="app">
        <firstVueComponent />
    </div>
</body>


% render_bundle 'chunk-vendors' %
% render_bundle 'main' %
% endblock %

django_template2.html

% extends 'header.html' %
% load render_bundle from webpack_loader %
% block content %

<body>
    <div id="app">
        <secondVueComponent />
    </div>
</body>


% render_bundle 'chunk-vendors' %
% render_bundle 'main' %
% endblock %

所以 Django 在这里处理 url:

from django.urls import path, include
from . import views

urlpatterns = [
    path('first_page/', views.first_page, name='first'),
    path('second_page/', views.second_page, name='second'),
]

所以这里我没有使用 Vue 来处理路由,而是在我需要它们的 Django 模板中加载同一应用程序的各个 Vue 组件。我的疑问:这是一种不好的做法吗?有什么我应该避免这样做的原因吗?

【问题讨论】:

可能是 XY 问题。你为什么不想解耦你的前端和后端?将这些与 Web API 分开作为抽象层是一种行业标准 有各种原因,比如我不想使用从 Django 渲染它的好处以及 Django 的所有安全优势,而且我比我更熟练 Django我在使用 Vue,所以我觉得从单独的前端处理身份验证不安全 我明白了。不过,仅从前端就很难破坏安全性。默认情况下,所有 Vue、React 和 Angular 都会保护您免受 XSS 的攻击,您需要非常努力地让自己陷入困境。并且无论 FE 是否紧密耦合,身份验证都由后端处理。 是的,主要问题是,将应用程序托管在两个不同的域上可能会使我在安全性方面失去很多 django 优势。我对在本地存储上存储 jwt 令牌有一些疑问,我认为这不是最安全的解决方案;有基于会话的身份验证,但我不知道它如何在两个不同的域上工作。另一件事是缺乏这方面的例子,最后最大的问题是我已经在这个环境中设置了应用程序,所以转向解耦将是一个非常重要的支点 是的,单独的域很糟糕,但是您可以使用带有 nginx proxy_pass 的域或通过 CDN 的方式(CloudFront、Cloudflare、Fastly 都可以做到)。对于本地开发,请使用 dev-proxy。有趣的是,不久前我进行了完全相同的讨论,也许我会在周末挤出一篇关于如何在一个域上设置 Django + SPA 的博客文章,这真的不是那么难。无论如何,如果您的设置适合​​您,请继续保持。回答您的原始问题路由应该发生在 SPA 中,否则您的 SPA 将不是 SPA。不过,您仍然需要从 Django 端返回 index.html 【参考方案1】:

我的疑问是:路由应该由 Django 处理还是应该由 SPA 中的 Vue 处理?

如果您要进行 SPA,您的 FE 需要知道路线,例如如果用户单击链接/项目,您的 FE 需要知道如何更新 URL。否则会出现页面刷新或错误的 URL。

所以这里我没有使用 Vue 来处理路由,而是在我需要它们的 Django 模板中加载同一应用程序的各个 Vue 组件。我的疑问:这是一种不好的做法吗?有什么我应该避免这样做的原因吗?

我认为您需要决定是否要构建 SPA。我的经验法则是,如果您的页面上有很多交互,或者您有一个专门从事 FE 的团队,SPA 会更好。完全分离 BE/FE 绝对是行业事实上的标准,但在 BE 上渲染大多数内容并拥有轻量级 FE 也不是犯罪,Stack Overflow 本身就是使用这种方法。

如果您要使用 SPA,将 FE URL 放入 BE 也没有多大意义(除非您正在执行诸如服务器端渲染之类的操作)。 BE 将提供一组 API URL(最终用户不可见),FE 将使用它们并提供一组用户可以看到的 FE URL。

是的,主要问题是,将应用程序托管在两个不同的域上可能会使我在安全性方面失去很多 django 优势。我对在本地存储上存储 jwt 令牌有一些疑问,我认为这不是最安全的解决方案;有基于会话的身份验证,但我不知道它如何在两个不同的域上工作。另一件事是缺乏这方面的例子,最后最大的问题是我已经在这个环境中设置了应用程序,所以转向解耦将是一个非常重要的支点

您的问题有多个答案。

1- 无需分隔域。您可以为所有 BE URL 加上 /api/ 前缀,然后在生产环境中,您可以使用 NGINX 或 Traefik 或负载均衡器等反向代理,...将两者分开。从长远来看,拥有单独的域更容易维护,但您需要不时处理 cookie/CORS 问题。

2- 如果您有单独的域,您可以使用 this settings 在子域的主域上设置 cookie

3- 无需在本地存储中使用 JWT 令牌。 IMO 不如拥有 httponly cookie。 Django session auth 默认开启httponly。这样,您安装的随机 npm 库或页面上的第 3 方脚本无法访问和窃取令牌。

4- 另外,Django CSRF 保护有点过时了,现在我们在浏览器上有samesite cookie。检查浏览器支持here。较新版本的 Django 默认为 Lax,可保护您在受支持的浏览器上免受 CSRF 的影响。因此,您可以关闭该保护以减少麻烦。

我个人认为您可以坚持使用基于 Django 会话的身份验证,无需向您的 FE 添加任何内容。 FE 只会调用/api/auth/login 并且会自动设置正确的cookie。

为了更加健壮,您可以添加一个类似/api/auth/me 的 API,它将当前登录的用户数据返回给 FE。当用户第一次访问您的网站时,FE 会调用它来了解用户是否登录。

【讨论】:

非常感谢。这非常有帮助。这里让我完全冻结的大问题是我是否应该使用 BE 来呈现页面或使用完整的 SPA。我的经验是将 Django 用于一切,因此在我的 Django 模板中的任何需要的地方渲染 Vue 组件并使用我的 urls.py 很方便,但有人告诉我这不是一个很好的方法。我正在创建的应用程序具有很高的交互性,但我没有两个团队在开发它。 我想去完整的 SPA,但最大的问题是 Django/Python 是我的领域,我对 Vue/JS 的经验较少,所以我自己构建身份验证不会让我觉得完全安全,另一个问题是缺乏关于这种方法的示例或来源,尽管看起来 SPA 是每个人都采用的方法 您现在仍然可以从 BE 提供您的 JS 文件。我不喜欢将 BE 与路由和 Vue 组件结合起来。即每个不以 /api/ 开头的 URL 都将返回一个 index.html,其中包含 JS 文件。 好的,但是如果我不使用 Django 处理 url,而是让 Vue 处理路由,但 Vue 应用程序仍然由 Django 使用 webpack-loader 呈现,该怎么办?与您提到的从 Nginx 渲染 Vue 应用程序有什么不同? 我不知道那个库的特点。通常的做法是从 Django 渲染 HTML 文件,并使用 NGINX 等其他工具提供静态/媒体文件。但是也可以从 Django 提供所有服务,您的一些工作人员将被阻止提供文件(效率低下,因为与 NGINX 相比,它们使用大量内存)。

以上是关于在 vue + django webpack 应用程序中处理页面的主要内容,如果未能解决你的问题,请参考以下文章

Vue.js img src 使用绝对路径(django+webpack)

Docker + Django + Vue.js + Webpack 如何正确配置 nginx?

Vue.js + vue.router + 历史模式 + Django = 错误

python框架django中结合vue进行前后端分离

Vue.js / webpack:当热重载编译它们时,如何清除旧的包 main-*.js 文件?

异常值:字符串索引必须是整数:渲染包错误 vue + django