原文链接: codeburst.io

在本教程中,我将向大家展示如何使用前端的 Vue.js 单页面应用和后端的 Flask 进行交互。

如果你只是想使用 Vue.js 库和 Flask 模板基本上是没什么问题的。但...好吧,其实还是有一个比较显而易见的问题:跟 Vue.js 一样,Jinji(模板引擎)也是使用双大括号来渲染页面,但已经有一个很好的解决方案 在这里 了。

我想要一个跟上面方案有点不同的例子。如果我要一个用 Vue.js(使用单页面组件,在vue-router 开启 HTML5 history 模式,还有使用其他一些非常棒的特性)框架的单页面和 Flask 做后台服务的应用?应该能按下面的要求工作:

  • Flask运行的服务可以访问 index.html 首页和 Vue.js 应用

  • 在前端开发环境,使用 Webpack 和它提供的很多非常棒的功能

  • 可以从前端的单页面应用访问 Flask 的 API 接口

  • 以 Node.js 服务运行的前端开发环境同样也可以访问 API 接口

这看起来很有趣,不是吗?那就让我们开始吧。

你可以在github上查看所有的源代码:

https://github.com/oleg-agapov/flask-vue-spa

客户端

我用 vue-cli 命令行工具搭建起 Vue.js 的基础框架。如果你还没有安装,可以运行:

$ npm install -g vue-cli

客户端和后端代码将会放到不同的文件夹下,初始化前端部分执行如下操作:

$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend

以下是我通过安装向导的项目设置:

  • Vue build — Runtime only (Vue 构建的版本 - 运行时)

  • Install vue-router? — Yes (安装 vue-router? - 是)

  • Use ESLint to lint your code? — Yes (使用 ESLint 校验你的代码? - 是)

  • Pick an ESLint preset — Standard (选择 ESList 的预置版本 - 标准)

  • Setup unit tests with Karma + Mocha? — No (使用 Karma + Mocha 设置单元测试? - 否)

  • Setup e2e tests with Nightwatch? — No (使用 Nightwatch 设置端到端测试? - 否)

下一步:

$ cd frontend
$ npm install
# after installation
$ npm run dev

现在你可以开始设置 Vue.js 应用了。让我们先来添加些页面吧。

添加 Home.vue 和 About.vue 到 frontend/src/components 文件夹。像如下简单添加些内容:

// Home.vue<template><div><p>Home page</p></div>
</template>

// About.vue<template><div><p>About</p></div>
</template>

我们将在本地验证它们(通过地址栏访问)。现在我们要改变 frontend/src/router/index.js 文件去一个个渲染我们的新组件:

import Vue from 'vue'
import Router from 'vue-router'const routerOptions = [{ path: '/', component: 'Home' },{ path: '/about', component: 'About' }
]const routes = routerOptions.map(route => {return {...route,component: () => import(`@/components/${route.component}.vue`)}
})Vue.use(Router)export default new Router({routes,mode: 'history'
})

现在如果输入 localhost:8080 和 localhost:8080/about 你应该看到相应的页面。

在我们构建生成项目静态资源前还需要修改它们的输出路径。在 frontend/config/index.js 找到下面的两行

index: path.resolve(__dirname, '../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../dist'),

然后成改如下内容

index: path.resolve(__dirname, '../../dist/index.html'),
assetsRoot: path.resolve(__dirname, '../../dist'),

所以, 包含 html/css/js 静态资源包的 /dist 文件夹和 /frontend 在同一级目录下。现在你可以运行 $ npm run build 去构建项目了

后端

Flask 后端,我将使用 3.6 版本的 python。在根目录 /flaskvue 文件夹下为后端代码和初始化虚拟环境创建新的子目录:

$ mkdir backend
$ cd backend
$ virtualenv -p python3 venv

开启虚拟环境执行(mac系统):

$ source venv/bin/activate

在 Windows 上开启请看这里 docs。

在虚拟环境中安装 Flask 如下:

(venv) pip install Flask

现在让我们开始写 Flask 服务器端代码。在根目录下创建 run.py 文件:

(venv) cd ..
(venv) touch run.py

然后添加以下代码到这个文件:

from flask import Flask, render_templateapp = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")@app.route('/')
def index():return render_template("index.html")

上面的代码和 Flask 入门教程 “Hello world” 上的代码稍有不同。最主要的不同点在于我们详细指明了前端的静态和模板文件夹输出到 /dist 文件夹。然后在根目录下运行 Flask 服务。

(venv) FLASK_APP=run.py FLASK_DEBUG=1 flask run

这将会在 localhost:5000 开启一个后台服务。FLASK_APP 指向服务启动文件,FLASK_DEBUG=1 将会以调试模式运行。如果没有错误,你将会看到熟悉的首页,这样,服务器就成功运行 Vue 应用了。

与此同时如果你试图访问 /about 页面将会出现一个错误。Flask 会抛出一个找不到请求地址的错误。实际上是因为在 vue-router 用了 HTML5 的 history 模式, 所以我们需要配置我们的后台服务去重定向所有的路由都跳转到 index.html 上。这在 Flask 上可以很简单做到。做如下修改:

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):return render_template("index.html")

现在地址 localhost:5000/about 将会重定向到 index.html 和 vue-router 将会在它自己内部处理。

添加 404 页面

因为在我们的后台服务里设置捕捉所有路由是非常困难的,所以我们用 Flask 捕捉 404 错误会重定向 所有 请求到 index.html(连同不存在的页面)。在 Vue.js 应用里处理未定义的路由。当然,所有的工作均可在我们的路由文件设置。

在 frontend/src/router/index.js 增加一行:

const routerOptions = [{ path: '/', component: 'Home' },{ path: '/about', component: 'About' },{ path: '*', component: 'NotFound' }
]

通配符 '*' 在 vue-router 里的含义是以上路由定义之外的情况。现在我们需要在 /components 文件夹新建 NotFound.vue 文件。我简单地创建它:

// NotFound.vue<template><div><p>404 - Not Found</p></div>
</template>

现在 通过 npm run dev 重新启动前台服务然后随意输入网址像 localhost:8080/gljhewrgoh。你应该看到 “Not Found” 两个单词。

添加后端 API 接口

我的 Vue.js/Flask 教程的最后一个例子将在后端创建一个 API 接口然后通过前端来调用它。我将创建一个随机返回数字1到100的简单端口。

打开 run.py 新增如下代码:

from flask import Flask, render_template, jsonify
from random import *app = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")@app.route('/api/random')
def random_number():response = {'randomNumber': randint(1, 100)}return jsonify(response)@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):return render_template("index.html")

我首先从 Flask 资源库导入 random 库和 jsonify 函数。然后我增加一个返回 JSON 数据格式的新路由 /api/random, 如下:

{"randomNumber": 36
}

你可以通过地址:localhost:5000/api/random 来测试这个路由。

到这里,服务端的工作已经完成了。该到客户端上场了。我将修改 Home.vue 组件来显示我的随机数字:

<template><div><p>Home page</p><p>Random number from backend: {{ randomNumber }}</p><button @click="getRandom">New random number</button></div>
</template><script>
export default {data () {return {randomNumber: 0}},methods: {getRandomInt (min, max) {min = Math.ceil(min)max = Math.floor(max)return Math.floor(Math.random() * (max - min + 1)) + min},getRandom () {this.randomNumber = this.getRandomInt(1, 100)}},created () {this.getRandom()}
}
</script>

在这一步,我将在客户端模拟随机数的生成。所以,组件的工作过程如下:

  • 初始变量 randomNumber 等于 0

  • 在 methods 部分,我们用 getRandomInt(min, max) 函数从指定区间返回一个数字, getRandom 函数将调用上一个函数生成一个值赋给 randomNumber

  • 之后在组件被创建时调用 getRandom 方法给 randomNumber 赋个初始数值

  • 在按钮点击事件里,我们将触发 getRandom 方法去得到一个数值

现在,在首页上你将看到由前端生成的随机数。让我们继续来连接后端。

我将用 axios 库来连接后端。它将允许我们创建能返回 Promise 对象的 HTTP 请求。我们先安装它:

(venv) cd frontend
(venv) npm install --save axios

再次打开 Home.uve,修改 <script> 部分代码:

import axios from 'axios'methods: {getRandom () {// this.randomNumber = this.getRandomInt(1, 100)this.randomNumber = this.getRandomFromBackend()},getRandomFromBackend () {const path = `[http://localhost:5000/api/random`](http://localhost:5000/api/random`)axios.get(path).then(response => {this.randomNumber = response.data.randomNumber}).catch(error => {console.log(error)})}
}

在文件顶部,我们先导入 axios 库。然后用 axios 去异步调用新方法 getRandonFromBackend 接收返回的结果。最后, getRandom 方法调用 getRandomFromBackend 去获取随机值。

保存文件,打开浏览器,再次运行前端开发服务器环境,刷新 localhost:8080 然后... 你应该看到控制台报了没有随机值的错误。但不用担心,一切正常运行中。我们得到 cors的错误,它的意思是我们的 Flask 后台 API 默认不对其他的域名和端口(我们的例子运行的是 Vue.js 应用)开放。当你用 npm run build 生成包然后打开 localhost:5000(Flask 服务)你会看到应用正常运行不再报错了。但如果每次在客户端改了一点东西都要重新构建包,显然不是很方便。

Flask 的 CORS 插件允许我们为访问 API 创建规则。插件叫 flask-cors,我们先来安装它:

(venv) pip install -U flask-cors

你可以通过阅读文档选择更好的方法来在你的服务器上开启 CORS。我这里将会用资源指定的方法应用 {"origins": "*"} 去允许所有 /api/* 下的路由(所以任何人都可以访问 /api 接口)。修改 run.py

from flask_cors import CORSapp = Flask(__name__,static_folder = "./dist/static",template_folder = "./dist")
cors = CORS(app, resources={"/api/*": {"origins": "*"}})

改好之后,你就可以从前端的开发环境调用 Flask API 接口了。

太神奇了 ✨!

现在你拥有了一个用你喜爱的技术完成的全栈应用。

后记

最后我想说说如何改进这个方案。

首先,在你代码里所有使用到的环境变量。主要是关于使用 FLASK_DEBUG 变量。我们在 CORS 设置中使用到它。例如,如果服务运行在开发环境设置 FLASK_DEBUG=1 你可以允许任何的请求源。如果不是,禁用 CORS 或者只允许可信源请求。

另外一个改进是避免在客户端硬编码 API 路由。也许你需要思考为 API 接口创建映射表。所以当你改变 API 路由,你所需要做的只是更新映射表。前端的调用接口将不需要改变。

还有个小建议 - 我通常同时开启至少3个终端窗口:一个运行 Flask,二个运行 Vue.js(第一个运行 Node.js 服务,第二个用来做项目构建打包)。

源代码:https://github.com/oleg-agapov/flask-vue-spa

最后非常感谢你的阅读!

使用 Vue.js 和 Flask 实现全栈单页面应用相关推荐

  1. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-2.启动项目 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习 ...

  2. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由、模型与数据库操作

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-3.路由.模型与数据库操作 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 ...

  3. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-8.使用mavoneditor(vue的markdown编辑器),并批量上传图片 技能学习:学习使用php(tp6框架) + ...

  4. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-6.用户登录(二),token验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本 ...

  5. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.优化后端接口,前端使用axios实现接口功能 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站 ...

  6. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-7.分类的模型关联和通用CRUD接口 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和 ...

  7. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-5.用户登录,密码的bcrypt(hash)加密与验证 技能学习:学习使用php(tp6框架) + vue.js,开发前端全 ...

  8. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境

    技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-1.工具和本地环境 技能学习 ...

  9. vue安装Postcss_Flask和Vue.js构建全栈单页面web应用【通过Flask开发RESTful API】

    前言: 看了一些国外的关于介绍flask和vue的前后端分离的文章,但没看到比较通俗易懂,代码完善的,直到昨天看到一篇新出的文章,而且内容非常棒,所以翻译过来,供大家一起学习. 原文来自Develop ...

最新文章

  1. 深入理解abstract class和interface
  2. pyspark rdd 基本操作
  3. GTK+ VS MFC
  4. Qt for ios 设置程序显示名称
  5. Android activity跳转动画,6种activity进入动画
  6. Flink中的Time与Window
  7. android 遍历sdcard,Android编程读取Assets所有文件(遍历每一个文件夹)并存入sdcard的方法...
  8. unity怪物攻击玩家减血_怪物猎人发布15周年 — 回顾历代封面怪之三大传奇怪物...
  9. Linux 命令(141)—— nmap 命令
  10. OSChina 周五乱弹 —— 姑娘馋的口水都留下来了。
  11. EonerCMS——做一个仿桌面系统的CMS(十四)
  12. 虚拟桌面与代理服务器的那些事
  13. VBox虚拟机在注册过程中可能报的错(一条龙服务) 打开虚拟文件失败、relaunching VirtualBox VM process 5 (Solved)等等
  14. 基于ARMv8架构的mini操作系统
  15. 美团运维SRE+运维开发一面面经汇总
  16. DATAGUARD原理
  17. ctf网络安全大赛web
  18. linux 查看主板sn_Linux系统查看硬件信息
  19. nb服务器协议,nb-iot协议详解
  20. 百病之源五脏为根(国粹---gt;中医;在此提倡自然疗法!)

热门文章

  1. 轻量型thttpd+php5
  2. python怎么打包_如何将一整个python工程打包
  3. cocos2dx游戏开发简单入门视频教程 (cocos2d-x)- 第1天
  4. Ruby命令之gem操作
  5. android分享,如何移除掉信息这项
  6. 输入用户名和密码登入到服务器,却显示指定的网络密码不正确,输入了好几次都是这样,这是怎么回事? 用户名和密码没问题 ,一直用的好好地今天就不行了...
  7. 小程序成长之路(一)-- 第一个完整demo
  8. 《解读NoSQL》——2.6 通过数据库分片获得水平扩展能力
  9. 递归查找特定路径的所有特定文件
  10. 简单的jQuery获取URL的?后带的参数