小复盘:Vue+Flask实战Web应用(未完待续)
本文主题
简单聊一聊实战中的一些体会好了,主要聊到如下主题,您感兴趣就随便看看:
- 路由
- 蓝图
- Vue单页面应用
- Vue-cli配置文件中的跨域和路由
〇、前提
项目相关环境
前端:http://127.0.0.1:8010
后端:http://127.0.0.1:8089
一、路由的秘密
- 先说一个现象
当我们在前端页面
http://127.0.0.1:8010/manage/flowerManage/proGather/list
进行某个操作时,在调试窗口看到它访问了后端接口
http://127.0.0.1:8010/api/flower/proGather/list
那么试试直接在Postman这种接口测试工具里输入该接口,得到了对应结果。
那么我们知道,后端其实是在8089端口启的服务呀?那我们再来试试在Postman中访问这个接口:
http://127.0.0.1:8089/api/flower/proGather/list
哈哈,出错啦。不过注意到没有,虽然postman上显示的status还是200,但是返回的Response里面有这么一行:
raise NotFound()\nwerkzeug.exceptions.NotFound: 404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
2.为什么呢?
先说说为什么通过前端服务端口,能访问到后端服务的api
。首先前端服务应该是做了路由的,所以会转到真正的后端接口上去。(如果说的不对欢迎指出)
路由其实蛮重要的,不仅仅是在我们写Web应用的时候。比如nginx就有提供专门的代理服务,这些以后有时间可以多多了解。
接下来看看后端为啥没有访问成功,这个是和我们的配置息息相关的。因此会放到后面“Vue-cli配置文件”的部分详细解释清楚,先来说下针对我这个项目,如何可以访问成功:
http://127.0.0.1:8089/flower/proGather/list
去掉路径里面的api
,就可以了……
(其实路由也还没写完,还想写下前端的路由。。)
二、蓝图
概念大家都懂了哇?说一下怎么用。
在create_app
的定义里面注册就好了,然后可以指定对应的url_prefix
。
对于一个Web应用,你可以图省事只使用一个蓝图,也可以使用多个蓝图分开不同的模块方便管理,记得注册就好了,在__init__.py
文件中,写了相关代码如下:
def create_app():
app = Flask(__name__)
app.config.from_object(BaseConfig)
app.logger.addHandler(config_log()) # 初始化日志
BaseConfig.init_app(app)
moment.init_app(app)
db.app = app
db.create_all()
login_manager.init_app(app)
scheduler.start() # 定时任务启动
# 注册多个蓝图模块
from app.admin import admin_module
from app.flower import flower_module
app.register_blueprint(admin_module, url_prefix='/admin')
app.register_blueprint(flower_module, url_prefix='/flower')
return app
那么再来看看蓝图模块是怎么写的呢?
目录结构是这个样子的(手工敲的,没有用目录生成的那种app,顺便求一下哪个生成目录结构好用啊):
app
-admin
__init__.py
admin_manage.py
-flower
__init__.py
flower_manage.py
__init__.py
看下admin目录下的两个文件;flower目录下也是类似的
app/admin/__init__.py
from flask import Blueprint
admin_module = Blueprint('admin_module', __name__)
from . import admin_manage
app/admin/admin_manage.py
from . import admin_module
@admin_module.route('/admin/add', methods=['POST'])
def add_user():
pass
好啦,照葫芦画瓢,你也会注册蓝图模块了!
三、理解Vue的单页面应用
很久以前用html做过网站,所以一直有一个惯性思维,觉得点击网页上的超链接跳来跳去的,就一定是在不同的页面间切换。
所以一开始也按照这个思路来学习Vue,看到别人案例中,有一个个的Vue文件,想当然的就理解成对应的页面了,后来才发现并非如此。
组件
Vue中有一个很重要的概念就是组件!官网都是这么介绍组件的:
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
<div id="components-demo">
<button-counter></button-counter>
</div>
new Vue({ el: '#components-demo' })
组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
你可以将组件进行任意次数的复用。
罗里吧嗦一大堆,那么它和单页面应用之间有什么联系?
(未完待续,发现写文章想解释的清楚一点,还真得多花时间,我尽量在本周内更新完这篇)
四、Vue-cli配置文件
在这个项目里,前端使用了Vue-cli脚手架。
如果你也直接用Vue-cli创建一个vue项目的话,可以在config目录下看到好几个.js文件,就是配置文件啦。
如果你是网上找来的项目,可能会略有不同,不过内容上都是类似的。
这次我们就来看看index.js
文件里的部分内容吧,由于把配置详解一遍很花时间,所以我们就聚焦一点,来揭开第一部分接口调用路径的谜底!
当然,有些项目的配置不一定保持了初始的名字,总之是含有module.exports = {
这行代码的配置文件就对了!
我这里是这样配置的:
module.exports = {
lintOnSave: true,
productionSourceMap: false,
chainWebpack: (config) => {
config.resolve.alias
.set('~', resolve('src'))
},
devServer: {
host: '127.0.0.1',
port: 8010,
proxy: {
'/api/': {
target: 'http://127.0.0.1:8089',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
},
css: {
loaderOptions: {
css: {
localIdentName: process.env.node_env == 'production' ? "[hash]" : '[path]_[name]_[local]_[hash:base64:5]',
camelCase: 'only'
},
sass: {}
},
}
};
首先看下这个devServer.proxy.changeOrigin
,它是为了解决跨域问题的一个设置。
changeOrigin: true, //开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题
那什么是跨域?
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域,如下例子:
域名:
主域名不同 http://www.baidu.com/index.html –>http://www.sina.com/test.js
子域名不同 http://www.666.baidu.com/index.html –>http://www.555.baidu.com/test.js
域名和域名ip http://www.baidu.com/index.html –>http://180.149.132.47/test.js
端口:
http://www.baidu.com:8080/index.html–> http://www.baidu.com:8081/test.js
协议:
http://www.baidu.com:8080/index.html–> https://www.baidu.com:8080/test.js
备注:
1、端口和协议的不同,只能通过后台来解决
2、localhost和127.0.0.1虽然都指向本机,但也属于跨域
综上,我目前的设置前后端的端口不一样,也算是跨域了,因此就要设置成true啦!
接着看下这段:
proxy: {
'/api/': {
target: 'http://127.0.0.1:8089',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
vue-cli的这个设置来自于其使用的插件http-proxy-middleware,github地址如下:
https://github.com/chimurai/http-proxy-middleware
官网文档中有这么一句:
proxy('/api', {...}) - matches paths starting with /api
这就说明,当我们的路径中含有/api
的时候,就会匹配到这里对应的配置啦。
那么pathRewrite
是干啥的呢?文档解释如下:
option.pathRewrite: object/function, rewrite target's url path. Object-keys will be used as RegExp to match paths.
并且给出示例:
// rewrite path
pathRewrite: {'^/old/api' : '/new/api'}
// remove path
pathRewrite: {'^/remove/api' : ''}
// add base path
pathRewrite: {'^/' : '/basepath/'}
// custom rewriting
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
而我们的配置中有写pathRewrite: { '^/api': '' }
,因此proxy时要把路径中的/api去掉。
OK,那么整体来解释一下devServer这段配置的意思!
devServer: {
host: '127.0.0.1',
port: 8010,
proxy: {
'/api/': {
target: 'http://127.0.0.1:8089',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
首先,127.0.0.1:8010
过来的请求,如果路径中含有/api
,就会被路由到127.0.0.1:8089
上去,并且把路径中的/api
去掉。
也就是说,当我们在前端访问了一个这样的接口:
http://127.0.0.1:8010/api/flower/proGather/list
实际上对应的是后端这个接口:
http://127.0.0.1:8089/flower/proGather/list
再来回到开头的问题上来,为什么使用postman访问http://127.0.0.1:8089/api/flower/proGather/list
会报404的错误?这下你就清楚了吧!