1.1 HTTP 异常主动抛出
# abort(404)
abort(500)
抛出状态码的话,只能抛出HTTP协议的错误状态码
1.2 捕获错误
例如:
同一处理状态码为500的错误给用户友好的提示
捕获指定异常(ZeroDivisionError)
# utils.errorhandler.py
from main import app
@app.errorhandler(500)
def internal_server_error(e):
return '对不起,服务器可能搬家了...'
@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除数不能为0'
# main.py
# 注意,不在一个文件中,得导一下,让异常处理的注册装饰器生效
from ustils import errorhandler
@app.route('/test_error')
def test_error():
# i = 1 /0
abort(500)
return 'test error'
在客户端和服务器交互过程中,有些准备工作或扫尾工作需要处理,比如:
为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设施的功能,即请求钩子。
请求钩子是通过 装饰器 的形式实现的,Flask支持如下四种请求钩子:
before_first_request
before_request
after_request
teardown_request
代码测试:
# ustils.hooks.py
from main import app
@app.before_first_request
def before_first_request():
#在处理第一个请求前执行
print('before first request...')
@app.before_request
def before_request():
#在每次请求前执行
print('before request')
#如果直接在这里返回一个响应,那么视图函数将不会被访问
#return '校验不合格'
@app.after_request
def after_request(resp):
#在每次请求后执行
print('after request')
# 在此函数中可以对响应值在返回之前做最后一步修改处理
resp.headers['python'] = 'flask'
#需要将参数中的响应在此参数中进行返回
return resp
@app.teardown_request
def teardown_request(resp):
#在每次请求后执行
print('teardown request')
# main.py
from ustils import hooks
@app.route('/test')
def test_hooks_function():
print('entry')
return 'test ok', 200, {'hook': 'ok'}
@app.route('/test2')
def test_hooks_function2():
print('entry2')
resp = make_response('test2 ok')
return resp
Flask中有两种上下文,即 请求上下文 和 应用上下文
Flask中上下文对象:相当于一个容器,保存了Flask程序运行过程中的一些信息
3.1 请求上下文(reuqest context)
在 flask 中,可以直接在视图函数中使用 request 这个对象进行获取相关数据,而 request 就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session
3.2 应用上下文(application context)
详情文档请移步
它的字面意思是 应用上下文,但它不是一直存在的,它只是request context 中的一个对 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的应用,它是伴 request 而生,随 request 而灭的。
应用上下文对象有:current_app,g
3.2.1 current_app
应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:
# 可在app中存入一些必要的信息
app.name='zhangsan`app'
@app.route('/operate')
def operate_app():
# 如果有多个app,而在实际使用时,并不能确定这是哪一个,就可以使用current_app,将其当做一个具体的app使用即可
return current_app.name
作用
current_app 就是当前运行的flask app,在代码不方便直接操作flask的app对象时,可以操作current_app就等价于操作flask app对象
手动推送情境
如果您尝试在应用情境之外访问 current_app ,或其他任何使用它的东西, 则会看到以下错误消息:RuntimeError: Working outside of application context.
如果在配置应用时发现错误(例如初始化扩展时),那么可以手动推送上下文。如此你就可以直接访问 app 。如:在 with 块中使用 app_context() , 块中运行的所有内容都可以访问 current_app 。:
def create_app():
app = Flask(__name__)
with app.app_context():
init_db()
return app
3.2.2 g对象
g 作为 flask 程序全局的一个临时变量,充当中间媒介的作用,我们可以通过它在一次请求调用的多个函数间传递一些数据。每次请求都会重设这个变量。
g 表示“全局”的意思,但是指的是数据在 情境 之中是全局的。 g 中的数据在情境结束后丢失,因此它不是在请求之间存储数据的恰当位置。使用 session 或数据库跨请求存储数据。
示例
from flask import g
@app.before_request
def authentication():
if request.path != '/login':
if 'user_info' not in g:
username = session.get('username', None)
# 将用户id或其他用户信息存起来
g.user_info = {'id': 123, 'username': username, 'fullname': '张三'}
def login_required(func):
def inner(*args, **kwargs):
if g.user_info is None:
# 用户未登录
return redirect('/login')
else:
return func(*args, **kwargs)
return inner
@app.route('/login', methods =['GET','POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
username = request.form.get('username')
pwd = request.form.get('password')
if 'zhangsan' == username and '111' == pwd:
session['username'] = username
return render_template('index.html', user_info = g.user_info)
else:
return render_template('login.html', msg={'登录失败'})
@app.route('/other')
@login_required
def other():
return jsonify(g.user_info)
g 的常见用法是在请求期间管理资源。
g
例如,您可以使用以下方案管理数据库连接:
from flask import g
def get_db():
if 'db' not in g:
g.db = connect_to_database()
return g.db
@app.teardown_appcontext
def teardown_db(exception):
db = g.pop('db', None)
if db is not None:
db.close()
在Flask程序未运行的情况下,调试代码时需要使用current_app、g、request这些对象,该如何使用?
app_context
app_context为我们提供了应用上下文环境,允许我们在外部使用应用上下文current_app、g
可以通过with语句进行使用
app = Flask(__name__)
app.name = 'my app'
with app.app_context():
print(current_app.name)
request_context
request_context为我们提供了请求上下文环境,允许我们在外部使用请求上下文request、session
可以通过with语句进行使用
app = Flask(__name__)
environ = {'wsgi.version':(1,0), 'wsgi.input': '', 'REQUEST_METHOD': 'GET', 'PATH_INFO': '/', 'SERVER_NAME': 'itcast server', 'wsgi.url_scheme': 'http', 'SERVER_PORT': '80'} # 模拟解析客户端请求之后的wsgi字典数据
with app.request_context(environ): # 借助with语句使用request_context创建请求上下文
print(request.path)