Flaks框架(Flask請求響應,session,閃現,請求擴展,中間件,藍圖)

[toc]
## 一:Flask請求響應

```python
# 導入模塊
from flask import Flask,jsonify
from flask import views

from flask import Flask
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response
app = Flask(__name__)
app.debug=True
```

```python
@app.route('/login.html', methods=['GET', "POST"])
def login():
```

### 1.請求相關信息

```python
request.method # 提交的方法
print(request.args.get('name')) # get請求提交的數據---GET
print(request.form) # post請求提交數據----POST
print(request.values) # get和post的彙總
print(request.query_string) # b'name=lqz&age=19'

request.args # get請求提及的數據
request.form # post請求提交的數據
request.values # post和get提交的數據總和
request.cookies # 客戶端所帶的cookie
request.headers # 請求頭
request.path # 不帶域名,請求路徑
request.full_path # 不帶域名,帶參數的請求路徑
request.url # 帶域名帶參數的請求路徑
request.base_url # 帶域名請求路徑
request.url_root # 域名
request.host_url # 域名
request.host # 127.0.0.1:500
request.files # 獲取文件對象
obj = request.files['the_file_name'] # .files獲取文件對象
obj.save('/var/www/uploads/' + secure_filename(f.filename))
```

### 2.flask新手四件套

```python
return "字符串"
return render_template('html模板路徑',**{})
return redirect('/index.html')
return jsonify({'k1':'v1'}) # 返回json格式
```

### 3.響應相關信息(響應response增加數據返回)

```python
# 將render_template('index.html')生成對象,寫到make_response對象內
response = make_response(render_template('index.html'))
response = make_response('hello')
# response是flask.wrappers.Response類型
response.delete_cookie('session')
response.set_cookie('name', 'lqz')
response.headers['X-Something'] = 'A value'
return response
# return "內容"

if __name__ == '__main__':
app.run(port=8888)
```

 

## 二:session

### 1.session與cookie簡介

```python
cookie:存放在客戶端的鍵值對
session:存放在客戶端的鍵值對
token:存放在客戶端,通過算法來校驗
```

### 2.在使用session之前必須現在設置一下密鑰

```python
app.secret_key="asdas" #值隨便
```

### 3.dajngo中session與Flask的session差別

```python
# 1.在django中發什麼三件事:
1,生成一個隨機的字符串 2 往數據庫存 3 寫入cookie返回瀏覽器

# 2.在flask中沒有數據庫,但session是怎樣實現的?
1.生成一個密鑰寫入這個cookie,然後下次請求的時候,通過這個cookie解密,然後賦值給session
```

### 4.session使用

```python
-增:session['name']=lqz
-查:session.get('name')
-刪:session.pop('name')
```

### 5.set_cookie其他參數

```python
key, 鍵
value='', 值
max_age=None, 超時時間 cookie需要延續的時間(以秒爲單位)如果參數是\ None`` ,這個cookie會延續到瀏覽器關閉爲止
expires=None, 超時時間(IE requires expires, so set it if hasn't been already.)
path='/', Cookie生效的路徑,/ 表示根路徑,特殊的:根路徑的cookie可以被任何url的頁面訪問,瀏覽器只會把cookie回傳給帶有該路徑的頁面,這樣可以避免將cookie傳給站點中的其他的應用。
domain=None, Cookie生效的域名 你可用這個參數來構造一個跨站cookie。如, domain=".example.com"所構造的cookie對下面這些站點都是可讀的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果該參數設置爲 None ,cookie只能由設置它的站點讀取
secure=False, 瀏覽器將通過HTTPS來回傳cookie
httponly=False 只能http協議傳輸,無法被JavaScript獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋)
```

### 6.整體代碼

```python
from flask import Flask,jsonify
from flask import views

from flask import Flask,session
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response
app = Flask(__name__)
app.debug=True
app.secret_key='sdfsdfsadfasdf'

app.session_interface

@app.route('/login.html', methods=['GET', "POST"])
def login():
session['name']='lqz'
response=make_response('hello')
# response.set_cookie('name', 'lqz')
return response


@app.route('/index', methods=['GET', "POST"])
def index():
print(session.get('name'))
return '我是首頁'
if __name__ == '__main__':
app.run(port=8080)
```

## 三:源碼分析SecureCookieSessionInterface

### 1.f'lask框架session源碼分析

![image-20220508105027958](https://s2.loli.net/2022/05/08/QHs7tWZOoKcIJFX.png)

### 2.分析SecureCookieSessionInterface

![image-20220508105227600](https://s2.loli.net/2022/05/08/u68pb2cseO1gj9h.png)

### 3.分析save_seesion響應與open_session請求來的時候

```python
1.save_seesion
-響應的時候,把session中的值加密序列化放大到了cookie中,返回到瀏覽器中

# save_session
"""
# 將session設置成字典類型序列化轉換成json字符串
val = self.get_signing_serializer(app).dumps(dict(session))
# 1.響應對象內設置session
response.set_cookie(
# 2.session的id
app.session_cookie_name,
# 3.session的value
val,
expires=expires,
)
"""


2.open_session
-請求來了,從cookie中取出值,反解,生成session對象,以後再視圖函數中直接用sessoin就可以了。

# open_session
"""
# 1.取出request.cookies中的value值
val = request.cookies.get(app.session_cookie_name)
# 2.將session的value值取出來反序列化
data = s.loads(val, max_age=max_age)
# 3.返回session(data)
return self.session_class(data)
"""
```

### 4.整體代碼

```python
from flask import Flask,jsonify
from flask import views

from flask import Flask,session
from flask import request
from flask import render_template
from flask import redirect
from flask import make_response
app = Flask(__name__)
app.debug=True
app.secret_key='sdfsdfsadfasdf'

app.session_interface

@app.route('/login.html', methods=['GET', "POST"])
def login():
session['name']='lqz'
response=make_response('hello')
# response.set_cookie('name', 'lqz')
return response


@app.route('/index', methods=['GET', "POST"])
def index():
print(session.get('name'))
return '我是首頁'
if __name__ == '__main__':
app.run(port=8080)
```

 

## 四:閃現

```python
-設置:flash('aaa')
-取值:get_flashed_message()

-假設在a頁面操作出錯,跳轉到b頁面,在b頁面顯示a頁面的錯誤信息
```

#### 1.示例:

```python
from flask import Flask,flash,get_flashed_messages,request,redirect

app = Flask(__name__)
app.secret_key = 'asdfasdf'


@app.route('/user', methods=['GET', "POST"])
def login():
try:
a=[1,2,3]
print(a[9])
except Exception as e:
print(e)
# 閃現普通使用(放在某個位置)
flash(str(e))
# 高級使用(閃現分類)
flash('超時錯誤', category="x1")
flash('xx錯誤', category="x3")
return response


@app.route('/error', methods=['GET', "POST"])
def error():
# 1.取出閃現(錯誤信息)
errors=get_flashed_messages()
# 2.取出閃現(高級使用分類)
errors=get_flashed_messages(category_filter=['x1'])
return render_template('error.html',errors=errors)

if __name__ == '__main__':
app.run()
```

![閃現](https://s2.loli.net/2022/05/08/yL4iVzH2AqUP9CJ.gif)

 

## 五:請求擴展

### 1 before_request

```python
# 請求來了會先走before_request
1.類比django中間件中的process_request,寫多個執行順序是從上往下
```

```python
#基於它做用戶登錄認證
@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

```python
# 從下往上,執行完了,響應走的時候執行
1.類比django中間件中的process_response,每一個請求之後綁定一個函數,如果請求沒有異常
```

```python
@app.after_request
def process_response1(response):
print('process_response1 走了')
return response
```

### 3 before_first_request

```python
# 只會執行一次,程序啓動以後,第一個訪問的會觸發,以後再也不會了
1.第一次請求時,跟瀏覽器無關
```

```python
@app.before_first_request
def first():
pass
```

### 4 teardown_request

```python
# 不管當次請求是否出異常,都會執行,出了異常,e就是異常對象,debug=False模式下,必須在上線模式下,False
1.每一個請求之後綁定一個函數,即使遇到了異常

# 作用:日誌記錄,
```

```python
@app.teardown_request
def ter(e):
pass
```

### 5 errorhandler

```python
# 只要是404錯誤,都會走它
1.路徑不存在時404,服務器內部錯誤500
```

```python
@app.errorhandler(404)
def error_404(arg):
return "404錯誤了"
```

### 6 template_global

##### 自定義標籤

```python
@app.template_global()
def sb(a1, a2):
return a1 + a2
#{{sb(1,2)}}
```

### 7 template_filter

##### 自定義過濾器

```python
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
#{{ 1|db(2,3)}}
```

### 8.總結:

```python
1 重點掌握before_request和after_request,

2 注意有多個的情況,執行順序

3 before_request請求攔截後(也就是有return值),response所有都執行
```

 

## 六:中間件(瞭解)

```python
from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
return 'Hello World!'
# 模擬中間件
class Md(object):
def __init__(self,old_wsgi_app):
self.old_wsgi_app = old_wsgi_app

def __call__(self, environ, start_response):
print('開始之前')
ret = self.old_wsgi_app(environ, start_response)
print('結束之後')
return ret

if __name__ == '__main__':
#1我們發現當執行app.run方法的時候,最終執行run_simple,最後執行app(),也就是在執行app.__call__方法
#2 在__call__裏面,執行的是self.wsgi_app().那我們希望在執行他本身的wsgi之前做點事情。
#3 所以我們先用Md類中__init__,保存之前的wsgi,然後我們用將app.wsgi轉化成Md的對象。
#4 那執行新的的app.wsgi_app,就是執行Md的__call__方法。
#把原來的wsgi_app替換爲自定義的,

app.wsgi_app = Md(app.wsgi_app)
app.run()
```

請求所有的流程

```python
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
#根據路徑去執行視圖函數,視圖類
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
#不管出不出異常,都會走這裏
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
```

 

 

 

## 藍圖

對程序進行目錄結構劃分

### 1.使用步驟

```python
1.實例化得到一個藍圖對象(可以指定直接的靜態文件和模板路徑)
2.在app中註冊藍圖(可以指定前綴)
3.以後再寫路由裝飾器,使用藍圖對象的.route
```

### 2.不使用藍圖,自己分文件

目錄結構:

```python
-templates
-views
-__init__.py
-user.py
-order.py
-app.py
```

app.py

```python
from views import app
if __name__ == '__main__':
app.run()
```

init.py

```python
from flask import Flask,request
app = Flask(__name__)
#不導入這個不行
from . import account
from . import order
from . import user
```

user.py

```python
from . import app
@app.route('/user')
def user():
return 'user'
```

order.py

```python
from . import app
@app.route('/order')
def order():
return 'order'
```

### 3.使用藍圖之中小型系統

詳見代碼:pro_flask_簡單應用程序目錄示例.zip

目錄結構:

```python
-flask_pro
-flask_test
-__init__.py
-static
-templates
-views
-order.py
-user.py
-manage.py

```

_*init*.py

```python
from flask import Flask
app=Flask(__name__)
from flask_test.views import user
from flask_test.views import order
app.register_blueprint(user.us)
app.register_blueprint(order.ord)
```

manage.py

```python
from flask_test import app
if __name__ == '__main__':
app.run(port=8008)
```

user.py

```python
from flask import Blueprint
us=Blueprint('user',__name__)

@us.route('/login')
def login():
return 'login'
```

order.py

```python
from flask import Blueprint
ord=Blueprint('order',__name__)

@ord.route('/test')
def test():
return 'order test'
```

### 4.使用藍圖之大型系統

詳見代碼:pro_flask_大型應用目錄示例.zip

總結:

```python
1 xxx = Blueprint('account', **name**,url_prefix='/xxx') :藍圖URL前綴,表示url的前綴,在該藍圖下所有url都加前綴

2 xxx = Blueprint('account', name,url_prefix='/xxx',template_folder='tpls'):給當前藍圖單獨使用templates,向上查找,當前找不到,會找總templates

3 藍圖的befort_request,對當前藍圖有效

4 大型項目,可以模擬出類似於django中app的概念
```

 

## 七:flask 項目演示

```python
# 1 創建一個庫movie
# 2 手動把表同步進去
-modes.py,解開註釋,右鍵執行

# 3 安裝項目依賴
-flask-sqlalchemy
-flask_script
-flask_redis
-flask_wtf
# 4 命令行中運行
python3 manage.py runserver
# 5 後臺管理中rbac控制
```

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章