flask
如何使用flask做vue的静态文件服务器?
原理: 让flask的静态文件与模板文件的根目录指向vue的静态文件地址.
from flask import Flask, render_template
def create_static_app(folder_path):
app = Flask(__name__,
static_folder = folder_path,
template_folder= folder_path)
@app.route('/', defaults={'rel_path': ''})
@app.route('/<path:rel_path>') #解析url地址
def path_serve(rel_path):
if rel_path.split(".")[-1] in ["js","css","ico","ttf","woff","map"]:
# 这些文件都从静态文夹里面获取
return app.send_static_file(rel_path)
elif not rel_path:
return render_template("index.html")
else:
raise ("cannot deal with {}".format(rel_path))
return app
if __name__ =="__main__":
app = create_static_app(r"D:\gdrive\js_swz\searchtest\app\dist")
app.run(host="192.168.1.9", port=9200, debug=True)
坑: flask的render_template方法会自动使用jinja2的语法来替换{{var}}.替换为空字符之后,vue再解析的时候就没有这些大括号了.最简单的处理方式是用app.send_static_file方法,这个方法不会去替换{{var}}
如何让flask自动热加载?
flask执行.run方法的时候,可以把debug选项改为True,这样可以热加载了.下图中我修改了main.py文件,然后flask感应到这个修改,执行了reload.
热加载示意
热更新的细节: 如果flask所以来的其他模块变化了,它自己会更新吗?
如何使用flask来处理post请求?
server端:
@app.route('/text', methods=['POST', 'GET'])
def convert_code():
"""
使用reqeust.get_data()方法才能得到传进来的json
:return:
"""
code_text = request.get_data()
json_data = json.loads(code_text.decode("utf-8"))
text_content = json_data['text']
web端(jinjia模板):
let xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","http://{{host_ip}}:5000/text",true);
xmlhttp.send(JSON.stringify({text:t.value}));
flask 如何做文件服务器
核心是使用send_from_directory这个函数来获取指定路径上的文件.
from flask import Flask
from flask import request, render_template, make_response, jsonify,send_from_directory
from run_fishsite.instance import config as instance_cf
app = Flask(__name__)
@app.route("/phtml/<path:rel_path>")
def show_phtml(rel_path):
return send_from_directory(instance_cf.phtml_dir, rel_path, as_attachment=False) # as_attachment代码是下载还是打开
上传文件会略微复杂一下,可以使用原生的flask,也可以使用插件:https://pythonhosted.org/Flask-Uploads/
如何使用flask_login实现登录?
实现思路: 1. 实现登录认证. 2. 实现登录状态保持. 3. 同一个url根据登录状态来返回不同结果.
在flask_login库中登录状态是由User类的对象保持的.不同的session会有不同的User类对象. 这个插件封装了session中的设置.
flask_login本身的函数提供了必要的操作流程,包括login_user函数, logout_user函数.
log_manager是为了给flask_login提供扩展,可以配置不同的回调函数.包括user的id设置,未登录提示,current_user等.
#coding=utf-8
import flask
import flask_login
# ------------------------- 配置 -------------------------
secret_key = 'super secret string' # flask要求任何与session相关的操作都需要密钥来确保安全性.
users = {'foo@bar.tld': {'password': 'secret'}}
app = flask.Flask(__name__)
app.secret_key = secret_key
# ------------------------- 定义User -------------------------
class User(flask_login.UserMixin): # 继承了基本的用户模型, User基本上就是一些属性的集合而已.
pass
# ------------------------- 配置login_manager-------------------------
login_manager = flask_login.LoginManager()
login_manager.init_app(app) # 绑定到app中去
@login_manager.unauthorized_handler
def unauthorized_handler():
return 'Unauthorized'
@login_manager.user_loader # 把user_loader挂载到login_manager上, 接受一个用户id作为参数,然后返回none或者user实例.
def user_loader(email):
print("I am user_loader")
if email not in users:
return
user = User() # 登录成功,新建一个User实例
user.id = email
return user
@login_manager.request_loader
def request_loader(request): # 不使用cookie的登录方法,可以直接从request对象中获取登录状态;flask-login会优先检查请求的cookie,当发现用户cookie不存在的时候才会根据request来验证
print("I am request_loader")
email = request.form.get('email')
if email not in users:
return
user = User()
user.id = email
# DO NOT ever store passwords in plaintext and always compare password
# hashes using constant-time comparison!
user.is_authenticated = request.form['password'] == users[email]['password'] # 对比密码
return user
# ------------------------- 使用flask_login-------------------------
@app.route('/login', methods=['GET', 'POST']) # 绑定登录页面
def login():
if flask.request.method == 'GET':
return '''
<form action='login' method='POST'>
<input type='text' name='email' id='email' placeholder='email'/>
<input type='password' name='password' id='password' placeholder='password'/>
<input type='submit' name='submit'/>
</form>
''' # 返回输入框
email = flask.request.form['email'] # 得到用户名(email)
if flask.request.form['password'] == users[email]['password']: # 校验密码
user = User()
user.id = email
flask_login.login_user(user) # 让用户登录进去, 此时会调用user_loader函数
return flask.redirect(flask.url_for('protected')) # 登录之后的重定向到/protected, url_for是一个类似于相对路径的概念.
return 'Bad login'# 密码不对
@app.route('/protected')
@flask_login.login_required # 需要登录
def protected():
return 'Logged in as: ' + flask_login.current_user.id # flask_login.current_user能够识别出当前的userid, flask_login维护一个比login_manager更上层的状态
@app.route('/logout')
def logout():
flask_login.logout_user()
return 'Logged out'
# ------------------------- 运行app-------------------------
app.run(host="192.168.1.4", port=5004, debug= True)
如何处理报错?
@app.errorhandler(401)
def page_not_found(e):
return Response('<p>Login failed</p>')
静态文件夹与路由的冲突
如果设置了静态文件夹,flask会自动根据url的地址来去静态文件中获取相应的文件.这样就忽略了用户自定义的路由函数.
app = Flask(__name__, static_folder=r"\\192.168.1.9\searchtest\app\static")
@app.route('/', defaults={'rel_path': ''})
@app.route('/path:rel_path>')
def path_serve(rel_path):
# mycode
此时所有get \static***这样的请求都会去静态文件夹中去找相应的文件.而忽略掉path_server
端口冲突的坑
某些端口能够启动flask,但是请求就是发不到flask上去.=>需要提前检查端口占用,被占用了就报错.
路由不识别根目录
@app.route("/dataeditor/<path:rel_path>")使用这样的路由会导致dataedtor这个根目录无响应.
坑: 默认的模板路径为templates而不是template
flask的自动多线程
使用了aiohttp这个异步请求的方法可以探知到flask自带多线程执行的.
案例1: 在view函数中,使用time.sleep(1), 然后连续发起两个请求,总耗时1.01秒左右.
案例2: 在view函数中使用全局变量,也不影响flask的时间消耗.
cout = [1]
@app.route("/")
def home():
html_str = """
cout[0] = cout[0] + 1
print(cout[0])
time.sleep(1)
# return html_str
return str(cout)
但是,如果调用了一个堵塞的io接口,那么会阻塞flask多线程的执行.例如tdx的交易接口.此时可以开启另一个tdx连接实例来降低延时.
坑: reqeust一般需要在view函数才可以引用.
flask多线程,可以使用 flask.copy_current_request_context这个装饰器,来获取当前的request中的信息.
参考:http://flask.pocoo.org/docs/1.0/api/#flask.copy_current_request_context
可以使用celery来实现后台进程,来不断地update数据.
http://flask.pocoo.org/docs/1.0/patterns/celery/
如何传递列表给flask
res = requests.get("http://192.168.1.4:5004/try_list", json=[1,3,4]) # 在flask 那边需要使用request.get_json来解析出列表来
坑: post请求被识别为get请求
如果post后面不加反斜杠的话,会被认为是get请求
requests.post(192.168.1.4:5000/ymarket, data=a_dict) # flask端会认为是get请求
坑: 在pycharm中启动flask
在pycharm中执行flask程序,会自动忽略app.run命令.因此需要在配置中配置好host与port
image.png