Flask & Vue 构建前后端分离的应用
最近在使用 Flask 制作基于 HTML5 的桌面应用,前面写过《用 Python 构建 web 应用》,借助于完善的 Flask 框架,可以轻松的构建一个网站应用。服务端的路由管理和前端模板页面的渲染都使用 Flask 提供的 API 即可,并且由于 werkzuge 提供了强大的开发功能,可以在运行时自动重新加载整个应用。如果使用 gevent 提供的 WSGIServer 作为服务器网关,在使用时需要进行一定的配置。此时仍然是由 Python 负责前后端的处理。
尽管 Jinja2 为界面渲染提供了诸多便利的方法,但修改模板中的 HTML 文件后都需要手动刷新 Chrome 浏览器以便观察变化。如果能给将界面的渲染从服务端分离出来,服务端只需要提供数据或相应的 API,界面由其他框架负责处理,那么将给程序开发带来极大的便利,可以考虑采用 Vue+Flask 的模式构建应用。
Vue 的使用非常灵活,既可以将其应用在现有网站的部分页面中(可兼容已经完成的网站项目),又可以将其作为一个单独的完整前端项目进行开发。由于我所构建的网站较小,而且使用 Flask 模板开发界面并不方便,最终我选择了将前端界面作为一个独立于服务端的项目进行开发,后端的数据或验证以 api 的形式开放给前端调用。
前后端分离的好处是,界面上的复杂的东西可以轻松的使用 Vue 框架处理,由 webpack 的 dev server 监听文件事件,界面改动后自动刷新浏览器,同时可以利用 Vue Devtoools 可以很方便的查看界面中的相应变量。另外 Vue 的文档比较全面(含有官方中文文档),并且入门门槛较低容易上手。
环境需要注意的是,环境对应用开发有一定的影响,有些文章中 Vue-cli 版本如果和你使用的不一样,将会有一些配置上的区别。
Python 3.6.7
服务端依赖项:flask 等,具体见文件
Vue 2.5.17
Vue 3.2.0
前端其他依赖项见文件
如果环境和你的有所不同,参照相应的官方文档进行操作。
Flask 后端尽管前端分离成的一个单独的项目,但是在生产环境中还是需要 Flask 提供路由访问生成好的 html 界面文件。不过访问页面的路由可以做的比较简单。
与其他的 Flask 应用没有区别,首先实例化一个 Flask 应用:
传入 Flask 的参数中 template_folder, static_folder 和 static_url_path 都是可以指定的,如果你需要兼容旧版本的应用,可以使用蓝图(Blueprint)并为其指定不同的模板路径和静态文件路径。在这里我用到了蓝图,实例化了 home 蓝图,并为其指定了一个不同的模板和静态文件路径(假设这个文件夹是我们稍后会用 Vue 构建出来的),这样的话就可以避免蓝图和应用的模板相互影响。
另一个要注意的地方是,必须在定义 home 蓝图的所有路由后再调用 app.register_blueprint(home), 否则将会出现找不到相应路由的错误提示。
我们这里将会构建单页应用,所以对于 home 的路由访问全部渲染到 home.html 页面上。
我们在项目根目录下面新建一个 templates 文件夹,在里面新建名为 home.html 的文件,添加以下内容:
<!DOCTYPE html> <html> <head> <title>Home Page with Jinja2 Template Engine</title> </head> <body> Hello, this is a home page rendered by Jinja2 Template Engine. </body> </html>现在运行这个 Python 脚本:
python app.py服务器程序默认运行在 127.0.0.1:5000 地址上,访问 :5000,我们能够在浏览器界面上看到 "Hello, this is a home page rendered by Jinja2 Template Engine."。注意这个位置有一个隐藏的坑:尽管我们设置了 home 蓝图的 template_folder 路径为 vtemplates(注意我们这个时候还没有创建这个文件夹),但是在访问 /home 路径时,渲染的文件却是 templates/home.html,看上去似乎不错,这让我们可以在蓝图和应用间共享模板,但是却会带来另一个问题。
接下来我们手动创建另一个文件夹 vtemplates,在里面新建名为 home.html 的文件,添加以下内容(稍后会使用 Vue-cli 自动构建 vtemplates 文件夹):
<!DOCTYPE html> <html> <head> <title>Home Page</title> </head> <body> Hello, this is a home page (it will be built by vue-cli commands). </body> </html>