1 背景
在用Vue编写完前端页面后,下一步打包并将它部署到线上服务器上,这样我们的页面才会被别人访问到。对于前端开发的同学,没有太多时间去系统学习后端的知识,因此快速部署一个后端服务就显得很重要了。
出于方便,前端同学可以使用Node.js进行后端开发,我个人也是这么习惯的。但是这次出于项目需要需要使用python进行简单的后端开发,那只能一边踩坑一边学习,比较痛苦,也因此在这里以前端的视角来讲述一下这个过程,希望能让大家少踩点坑。
2 准备
- 将编写好的Vue工程进行打包,命令为
npm run build,生成一个dist文件夹。 - 任意找一个位置,新建一个文件夹serve,结构如下
├─ serve | ├─app.py 配置的服务器的文件 | ├─dist 前端资源夹 | ├─controller 接口配置文件夹 - 将Vue打包出的dist文件夹中的内容放在serve/dist文件夹下
3 最简单的Flask程序
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
if __name__ == '__main__':
app.run(debug=True,port=8100)
- 安装flask:
pip install flask引入flaskfrom flask import Flask - 注册app
app = Flask(__name__)这个记住写法就行 - 配置服务器运行在本机8100端口,debug设置为True有利于调试,只需要按下调试就可以自动重启服务,类似于nodemon的作用
if __name__ == '__main__':
app.run(debug=True,port=8100)
- 这个部分作用就是注册路由'/'并绑定到函数hello_world上。实现的效果就是,当我们访问8100端口(在本地就是127.0.0.1:8100)的时候,hello_world函数会被执行,前端会拿到return函数里面的值。
@app.route("/")
def hello_world():
return xxx
return函数可以return一个json数据也可以return一个HTML文件,后续就可以用这个方法配置接口并部署前端静态页面。
4 静态页面部署 history路由的解决 接口配置
静态页面部署
第一步修改静态文件的路径,配置到dist文件夹中
app = Flask(__name__, static_folder='dist')
使用app.send_static_file发送index.html,这样当浏览器访问8100端口的时候就可以出现网页内容了
@app.route('/')
def index():
print('index')
return app.send_static_file('index.html')
其实这上面的过程达到的效果就是npm run serve的效果,但是会出现一个问题,如果前端配置的路由是history而不是hash,那么需要额外针对这个进行解决
history路由的解决
总体的思路就是如果遇到没有定义的path,就跳回到index.html,让前端去处理,这里特别避开了CSS JS IMG文件夹以及ico文件,防止代码要访问的时候出现问题。
@app.route('/<path:path>')
def history(path):
if path.startswith('css/') or path.startswith('js/')\
or path.startswith('img/') or path == 'favicon.ico':
return app.send_static_file(path)
else:
print(path)
return app.send_static_file('index.html')
同时,网上有些教程推荐的配置是
app = Flask(__name__,static_folder='dist',static_url_path="")
这样写的话,在路由history配置的时候会出问题,如果非要写static_url_path,应该写成
app = Flask(__name__,static_folder='dist',static_url_path="/dist")
接口配置
@app.route('/hello',methods=["GET"])
def hello():
return json.dumps({'status':0,'message':'成功访问Hello'}, ensure_ascii=False)
这里配置了一个GET接口'127.0.0.1:8100/hello',通过postman测试,发现可以使用
代码
from flask import Flask
from flask_cors import CORS
from config import Config
import json
app = Flask(__name__,static_folder='dist',static_url_path="/dist")
app.config.from_object(__name__)
app.config['JSON_AS_ASCII'] = False
CORS(app)
@app.route('/hello',methods=["GET"])
def hello():
return json.dumps({'status':0,'message':'成功访问Hello'}, ensure_ascii=False)
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/<path:path>')
def history(path):
if path.startswith('css/') or path.startswith('js/')\
or path.startswith('img/') or path == 'favicon.ico':
return app.send_static_file(path)
else:
print(path)
return app.send_static_file('index.html')
if __name__ == '__main__':
app.run(debug=True, port=8100)
5 提升
显然,代码都放在同一个文件中是不可以接收的,那么就把接口的部分先拆分出来。
-
这里使用flask的蓝图来拆分不同的接口,在准备阶段我们已经创建了一个controller文件夹,在文件夹中新建一个
hello.py -
引入Blueprint,并创建一个Blueprint对象
import json
from flask import Blueprint
# 创建了一个蓝图对象
hello = Blueprint('hello',__name__)
这个hello是等会儿要暴露出去的一个变量
- 配置两个post接口
@hello.route("/world", methods=["POST"])
def world():
return json.dumps({'status':0,'message':'Hello world'},ensure_ascii=False)
@hello.route("/flask", methods=["POST"])
def flask():
return json.dumps({'status':0,'message':'Hello flask'},ensure_ascii=False)
- 在app.py中使用
from controller.dialog import dialog
app.register_blueprint(dialog, url_prefix='/hello')
如果要访问这个hello.py里面的接口,必须是'/hello'开头的,比如说'/hello/world'
- 使用postman测试
代码汇总
#app.py
from flask import Flask, render_template
from flask_cors import CORS
from config import Config
from controller.hello import hello
import json
# 访问静态前缀暂时用不到
app = Flask(__name__,static_folder='dist',static_url_path="/dist")
app.config.from_object(__name__)
app.config['JSON_AS_ASCII'] = False
CORS(app)
app.register_blueprint(hello, url_prefix='/hello')
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/<path:path>')
def history(path):
if path.startswith('css/') or path.startswith('js/')\
or path.startswith('img/') or path == 'favicon.ico':
return app.send_static_file(path)
else:
print(path)
return app.send_static_file('index.html')
if __name__ == '__main__':
app.run(debug=True, port=8100)
#hello.py
import json
from flask import Blueprint
# 创建了一个蓝图对象
hello = Blueprint('hello',__name__)
#####################################################################################
@hello.route("/world", methods=["POST"])
def world():
return json.dumps({'status':0,'message':'Hello world'},ensure_ascii=False)
#####################################################################################
@hello.route("/flask", methods=["POST"])
def flask():
return json.dumps({'status':0,'message':'Hello flask'},ensure_ascii=False)