一. 請求擴展
1. before_request
作用: 類比django中間件中的process_request,在請求到來執行路由函數之前先執行. 但是如果有多個順序是從上往下執行.
應用: 基於它做用戶登錄認證
注意: 如果before_request的返回值不是None的清空下, 返回的而是別的值, 那么后續的請求都不會執行,本次請求直接返回, 如果定義了after_request那么會接着它執行, 最終本次請求響應結束.
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')
2. after_request
作用: 類比django中間件中的process_response,如果請求沒有出現異常的情況下, 會在請求返回return之前執行. 但是如果有多個順序是從下往上執行.
@app.after_request # 后執行
def process_response1(response):
print('process_response1 走了')
return response
@app.after_request # 先執行
def process_response2(response):
print('process_response2 走了')
return response
3. before_first_request
作用: 項目啟動起來接收到第一次請求時執行.
應用: 項目初始化用來保證以后項目只要不重啟就不再繼續執行.
@app.before_first_request
def first():
print('我的第一次')
4. teardown_request
作用: 在每一個路由函數執行完畢之后執行,即使遇到了異常也會執行. (提示: 返回reutrn沒有任何的效果, 不能控制返回的結果)
應用: 記錄日志
@app.teardown_request
def ter(e): # e就是上一個路由函授執行過程中出現被捕獲的異常信息.
print(e)
print('我是teardown_request ')
5. errorhandler
作用: 綁定錯誤的狀態碼進而可以捕獲服務器的錯誤, 並返回對應的錯誤頁面.
@app.errorhandler(500)
def error_500(arg):
return render_template('error.html', message='500錯誤')
@app.errorhandler(404)
def error_404(arg):
return render_template('error.html', message='404錯誤')
6. template_global
作用: 全局的標簽, 在任意的html頁面中就可以直接使用, 不需要在render_template中傳遞參數以后才能使用.
@app.template_global()
def sb(a1, a2):
return a1 + a2
# html頁面中直接使用, 不需要傳遞參數.
{{ sb(1,2) }}
7. template_filter
作用: 全局的過濾器, 在任意的html頁面中就可以直接使用, 不需要在render_template中傳遞參數以后才能使用.
@app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3
{{1|db(2,3)}}
8. 模板上下文
@app.context_processor
def context_processor():
return {"username":"馬克菠蘿"}
app對象調用context_processor作為模板上下文處理器,視圖函數在每一次調用render_template('')的時候都會為模板傳入@app.context_processor裝飾器所裝飾函數的返回值,該返回值作為模板變量,但是返回值一定要為字典,如果不想返回任何值,可以返回空字典,否則會報錯,返回值可以設置為模板經常要使用的變量,減少了代碼的冗余,提高了代碼的可維護性。
# html頁面中直接使用, 不需要傳遞參數. 其中1傳遞給a1, 2傳遞給a2, 3傳遞給a3. (提示: Django中的過濾器最多只可以傳遞二個參數)
二 flask的中間件:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
print('視圖函數中')
return 'hello world'
class my_middle:
def __init__(self,wsgi_app):
self.wsgi_app = wsgi_app
def __call__(self, *args, **kwargs):
print('中間件的代碼上')
obj = self.wsgi_app( *args, **kwargs)
print('中間件的代碼下')
return obj
if __name__ == '__main__':
app.wsgi_app = my_middle(app.wsgi_app)
# app.wsgi_app(environ, start_response)
app.run()
# 梳理一下 根據werkzeug我們可以知道 每次請求必然經歷了app()
# 所以我們要查看Flask的源碼找到__call__方法
# 找到了__call__方法后發現執行了return self.wsgi_app(environ, start_response)
# 然后flask里面所有的內容調度都是基於這個self.wsgi_app(environ, start_response),這就是就是flask的入口
# 如何實現中間件呢? 原理上就是重寫app.wsgi_app,然后在里面添加上一些自己想要實現的功能。
# 首先分析 app.wsgi_app需要加括號執行 所以我們把app.wsgi_app做成一個對象,並且這個對象需要加括號運行
# 也就是會觸發這個對象的類的__call__()方法
# 1 那么就是app.wsgi_app=對象=自己重寫的類(app.wsgi_app) ,我們需要在自己重寫的類里面實現flask源碼中的app.wsgi_app,在實例化的過程把原來的app.wsgi_app變成對象的屬性
# 2 app.wsgi_app() =對象() = 自己重寫的類.call()方法
# 3 那么上面的代碼就可以理解了,在自己重寫的類中實現了原有的__call__方法
