vue dve环境static无法被外部访问_Python构建RESTful网络服务[Flask篇:用Flask+Vue.js打造全栈单页面应用]...

10c9e08046309f71b57128200211db67.png

前言

本来在着手写关于使用Flask构建RESTful网络服务的文章,正好看到一篇相关文章,提供了一个Flask+vue构建全栈单页面应用的例子,觉得不错,就在此分享给大家。

原文载于https://codeburst.io/full-stack-single-page-application-with-vue-js-and-flask-b1e036315532

作者Oleg Agapov ,似乎是俄语使用者,不过这篇文章是用英文写的,文风细致友好,可以一读。考虑到一些朋友不方便查看外网,特此翻译并转载到知乎专栏。以下是全文及几条网友问答翻译。

注意:阅读本文需要一点点的Flask知识和一点点的Vue知识(只要你看过任何一点点新建一个Flask应用且看过任何一点点新建一个Vue应用的文章,就满足了本条要求)

另外:Python构建RESTful网络服务[Django篇] 没有完结,仍在连载中,见专栏更新。


用Flask+Vue.js打造全栈单页面应用

在本教程中,我将向您展示如何将Vue.js单页面应用程序与Flask后端整合起来。

基本上,如果你只想在Flask模板中使用Vue.js库,那么问题不大。唯一值得注意是Jinja(模板引擎)使用双花括号来渲染变量,而Vue插值也使用双花括号,解决这问题可以见这里https://github.com/yymm/flask-vuejs。

而本文要说的是另一种情况:我需要一个使用Vue.js构建的单页面应用程序(使用单页面组件、history模式的vue-router和其他优秀特性),并通过Flask服务器提供服务。简而言之,应该是这样工作的:

  • Flask伺服一个index.html,这是我的Vue.js应用入口文件
  • 使用Webpack进行前端工程化开发
  • 可以从SPA访问Flask的API端点
  • 使用Node.js运行前端项目时,也可以访问Flask的API端点

这种情况该怎么办呢?听起来是不是很有趣,说干就干吧!

完整的源代码见于:https://github.com/oleg-agapov/flask-vue-spa

客户端

我使用vue-cli生成基本的Vue.js应用程序。如果你还没有安装Vue.js,只要运行:

$ npm install -g vue-cli

客户端和后端代码将被分别放到不同的文件夹。初始化前端部分运行如下:

$ mkdir flaskvue
$ cd flaskvue
$ vue init webpack frontend

通过安装向导,按如下设置是:

  • Vue build — Runtime only #仅在运行时构建
  • Install vue-router? — Yes # 使用vue-router提供的前端路由
  • Use ESLint to lint your code? — Yes # 使用ESLint检查代码
  • Pick an ESLint preset — Standard # 设置ESLint为标准模式
  • 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 文件夹。简单填写一下,就像这样:

<

现在要构建前端路由,前端应用要知道怎么处理我们我们在浏览器地址栏中填写地址。在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 可以看到相应的页面。

e656e7fd173a4f6c77f0f284bbaee4ee.png

我们现在几乎已经可以构建包含一系列静态文件的前端应用了,不过在此之前,我们还要重设前端应用文件的路径。在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 

来构建项目。

c14010e36c70f06b80c26f7028b04f7e.png

后端

Flask 服务使用的Python版本为3.6。在 /flaskvue 文件夹中,为后端代码创建新的子文件夹,并在其中初始化虚拟环境:

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

启用虚拟环境运行(在macOs上):

$ source venv/bin/activate

要在Windows中激活,见于http://pymote.readthedocs.io/en/latest/install/windows_virtualenv.html。

在虚拟环境下安装Flask

(venv) pip install Flask

现在让我们为Flask server编写代码。在根目录中创建run.py文件:

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

添加如下代码到这个文件:

from 

我们的代码与Flask starter的“Hello world”代码略有不同。主要的不同之处在于,我们指定了静态文件和模板文件目录为/dist文件夹,就是前文构建的前端应用所在文件夹。在Flask应用所在文件夹运行Flask服务器:

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

这将在localhost:5000上启动一个web服务器。FLASK_APP指向服务器启动文件,FLASK_DEBUG=1将在调试模式下运行。如果一切正常可以看到我们熟悉的界面,就是之前构建的前面项目一样的页面。

但是,如果试图进入/about页面,页面就会报错。Flask抛出一个错误,说请求的URL没有找到。这是因为,我们在前端路由中使用了HTML5 history模式,当我们访问Flask的/about页面时,后端路由并不知道要去哪里找我们想要的页面。我们需要配置web服务器将所有路由重定向到index.html。在Flask里很容易做到。将现有路由修改为:

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

现在URL localhost:5000/about将被重定向到index.html,vue-router将自己处理它。

添加 404 页面

现在,无论对Flask服务器发送什么样的请求,它都不会返回404页面了,因为即使找不到资源,它也只会把url交给前端应用,而不会返回404状态。所以404状态的响应,要由Vue.js完成。

在 frontend/src/router/index.js 加上如下代码行:

const 

这里的 path '*' 是 vue-router 的通配符,表示除以上url以外的路由,都交给NotFound。现在在 /components 创建 NotFound.vue 文件,就简单写一下 好了。

<

现在再次使用npm运行dev前端服务器,并尝试输入一些无意义的地址,比如localhost:8080/gljhewrgoh。应该看到我们的“Not Found”信息。添加API端点

使用Flask伺服所有服务

这是本教程的最后一步,我们在服务器端创建API并在客户端使用它。我将创建一个简单的端点,它将返回一个从1到100的随机数。

打开run.py并添加:

from 

首先导入 random 库和 jsonify 函数。然后创建一个 /api/random 对应的视图返回一个JSON 响应,如:

{
  

现在访问 localhost:5000/api/random可以得到正确的Json响应。

服务器端工作已经完成了,是时候在客户端展示了。我们来改写Home.vue。

<

在目前,我只是在客户端模拟随机数生成过程。所以,这个组件是这样工作的:

  • 初始化变量随机数为0
  • 在method部分,我们有getRandomInt(min, max)函数,它将返回一个指定范围内的数字,getRandom函数将调度之前的函数并将其值赋给randomNumber
  • 创建组件方法后,将调用getRandom初始化randomNumber
  • 在按钮点击事件上,我们将发送getRandom方法来获取新号码

现在在首页你应该看到我们的随机数。但它是前端自己产生的,不是后端传过来的,现在我们来改写代码,从后端获取数据。

为此,我将使用axios库。它允许我们发出HTTP请求并返回带有JSON answer的JavaScript Promise。安装:

(venv

打开Home.vue,修改script,

import 

首先我们要导入axios库。然后有一个新的方法getRandomFromBackend,它将使用axios异步地从API获取结果。最后,getRandom方法现在应该使用getRandomFromBackend函数来获得一个随机值。

保存文件,运行前端开发服务器(localhost:8080),访问首页,你应该会在控制台看到一个错误,没有随机值。但别担心,只是发生了CORS错误(跨站请求被拒绝),这意味着我们的Flask服务器API默认情况下是对其他web服务器关闭的(在我们的例子中,“其他web服务器”是指运行Vue应用程序的Node.js服务器)。我们可以使用npm的build命令构建一个应用,并打开localhost:5000 (Flask服务),就可以看到我们的成果。但是,每次对客户端应用程序进行一些更改时,都要重新构建,并不十分方便。

我们使用Flask的CORS 插件,它将允许我们为API访问创建一个规则。插件是flask-cors,安装:

(venv

我将使用特定于资源的方法,并将{" origin ": " * "}应用于所有/api/*路由(这样每个人都可以使用我的/api端点)。更多配置见CORS相关文档。

在run.py:

from 

更改后,可以直接从前端开发服务器调用Flask api。

实际上,如果通过Flask提供静态文件,那么就不需要CORS扩展。感谢Carson Gee(https://github.com/carsongee)的工作。在生产环境中提供静态文件,我们可以这样做:

import requests


@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
def catch_all(path):
    if app.debug:
        return requests.get('http://localhost:8080/{}'.format(path)).text
    return render_template("index.html")

简洁而优雅!魔法✨!

现在,你已经使用你喜欢的技术构建了一个全栈应用程序了。

后记:

最后,我想谈谈如何改进这个解决方案。

首先,只有在希望为外部服务器提供对API端点的访问权限时,才使用CORS扩展。否则,只需使用代理前端开发服务器的技巧。

另一个改进是避免在客户端使用硬编码的API路由。也许你需要考虑一些带有API端点的字典。当你改变你的API路由时,你只需要刷新一个字典。前端仍然有一个有效的端点。

通常在开发过程中,我们将至少有两个终端窗口:一个用于Flask,另一个用于Vue.js。在生产中,我们将避免为Vue运行单独的Node.js服务器。

代码: https://github.com/oleg-agapov/flask-vue-spa感谢阅读!

译者摘选的网友问答

问:为什么不直接用SPA连到RESTful API,而用Flask代理呢?

答:因为我想在生产环境中,只用启用一个服务,而不是两个服务。用Flask代理,我就不用启动一个Node.js服务了。

问:你用什么IDE开发?

答:我用好用的VS Code,它对Python和Vue都有很好的支持。

问:我在处理登录逻辑时,使用Flask重定向到了登录视图,但是出现了错误?

答:后端只提供数据,你应当在Vue端设置这一重定向。

问:在开发环境,使用两个服务,是因为可以使用前面服务的热重载是吗?

答:基本是的。

问:我把项目部署到heroku上,需要对这个设置执行什么特殊的操作吗?我部署的似乎没能正常工作。我添加了一个Procfile并安装了gunicorn,复制了这个包到根文件夹,并添加了一个heroku/nodejs构建包 ……

答:我没有在heroku上部署过,好像是vue的路由问题。你看看是不是没有重定向到vue的index.html文件上。(译者注,看原提问者的描述,应该是使用Nginx之类的服务器时,没有正确伺服静态文件。)


本文为Flask+Vue整合开发提供了一个很好的模板,虽然只是一个很小很小的应用,但是却可以在这种模型思路下,搭建完整的前后端分离项目。文章作者写JS似乎不喜欢写分号,代码也写得极为简单(甚至不完整,完整代码见于其Github),但不妨碍正想使用Python结合前端框架Vue编写Web项目的读者汲取一些有用的思路。

Python构建RESTful网络服务[Django篇]仍在连载中,后续会讨论测试与API文档。希望在以的后的文章中,能继续讨论Flask、Tornado等其它Python Web框架的RESTful网络服务开发。

文章列表

  • Python构建RESTful网络服务[Django篇:Vue+Django构建前后端分离项目]: https://zhuanlan.zhihu.com/p/54776124
  • Python构建RESTful网络服务[Django篇:基于函数视图的API]:https://zhuanlan.zhihu.com/p/55562891
  • Python构建RESTful网络服务[Django篇:使用PostgreSQL替代SQLite]:https://zhuanlan.zhihu.com/p/55903530
  • Python构建RESTful网络服务[Django篇:基于类视图的API]:https://zhuanlan.zhihu.com/p/57024322
  • Python构建RESTful网络服务[Django篇:基于视图集的API]:https://zhuanlan.zhihu.com/p/57791697
  • Python构建RESTful网络服务[Django篇:用户接入控制,认证与权限]:https://zhuanlan.zhihu.com/p/58426061
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值