【Flask】請求與響應,session使用,閃現,非同步,藍圖
阿新 • • 發佈:2022-12-12
目錄
1. django不使用內建的app,使用drf,如何處理?
1. 註釋掉所有內建app
2. 註釋掉所有內建中介軟體
3. 寫入drf的配置項
REST_FRAMEWORK = {
"UNAUTHENTICATED_USER": None
}
2. 請求與響應
2.1 請求物件
from flask import Flask, request app = Flask(__name__) app.debug = True @app.route('/') def index(): # 請求物件,是全域性的,需要匯入,這個全域性的request,在哪個檢視函式中,就是當次的request物件,不會亂 # request.method 提交的方法 print(request.method) # request.args get請求提及的資料 print(request.args) print(request.args.get('name')) # request.form post請求提交的資料 print(request.form) # request.values post和get提交的資料總和 print(request.values) # request.cookies 客戶端所帶的cookie print(request.cookies) # request.headers 請求頭 print(request.headers) print('------') # request.path 不帶域名,請求路徑 print(request.path) # request.full_path 不帶域名,帶引數的請求路徑 print(request.full_path) # request.script_root print('服務端:', request.script_root) # request.url 帶域名帶引數的請求路徑 print(request.url) # request.base_url 帶域名請求路徑 print(request.base_url) # request.url_root 域名 print(request.url_root) # request.host_url 域名 print(request.host_url) # request.host 127.0.0.1:500 print(request.host) # request.files print(request.files) # obj = request.files['files'] # obj.save('./xx.jpg') print(request.data) # django的body return 'hellod' if __name__ == '__main__': app.run()
2.2 響應物件
@app.route('/',methods=['GET','POST']) def index(): # 1四件套 # -render_template # -redirect # -jsonify # -'' # 2寫入響應頭-->沒有響應物件,先做出一個響應物件 # from .wrappers import Response res='helloe' res=make_response(res) # 往Response的物件中,放入響應頭 res.headers['name']='lqz' # 3 寫入cookie # res.set_cookie('xx','xx') res.delete_cookie('xx') ''' 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獲取(不是絕對,底層抓包可以獲取到也可以被覆蓋) ''' return res
2.3 前後端分離和混合
1. 前後端混合,cookie 是後端寫入的
res.set_cookie('xx','xx') 混合都是這麼寫的,這樣寫了,瀏覽就會把cookie儲存到cookie中
本質是後端把cookie放到響應頭中,瀏覽器讀到響應頭中有cookie,把cookie寫入到瀏覽器中
2. 前後端分離後
直接把客戶端要存到cookie中的資料,放到響應體中
前端(瀏覽器,app,小程式),自己取出來,放到相應的位置
瀏覽器使用js自己寫入到cookie
app 自己使用程式碼寫入到某個位置
3. session的使用和原理
3.1 session的使用
# 放值 檢視函式中
匯入全域性的session
session['name']='lqz'
# 取值 檢視函式中
匯入全域性的session
print(session['name'])
3.2 原始碼分析
# django 的這一套,都在 from django.contrib.sessions.middleware import SessionMiddleware
# flask 在flask原始碼中
-請求來了,會執行 app()
# 整個flask,從請求進來,到請求走的整個流程
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
try:
try:
ctx.push() # 它的原始碼
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
ctx.pop(error)
# ctx.push 的 373行左右
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
# app.session_interface 就是Flask物件中有個session_interface物件
SecureCookieSessionInterface()
-open_session:請求來了,從cookie中取出三段串,反序列化解密放到session中
-save_session:請求走了,把session字典中的值,序列化加密,放到cookie中
# open_session:請求來了執行
def open_session(self, app, request) :
s = self.get_signing_serializer(app)
if s is None:
return None
# val 就是取出的三段:eyJhZ2UiOiIxOSIsIm5hbWUiOiJscXoifQ.Y5ac9g.vOomQFqFuaqXWqRQhvSNyc61UIk
val = request.cookies.get('session')
if not val:
return self.session_class()
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
# 請求走了,執行save_session
def save_session(self, app, session, response):
name = self.get_cookie_name(app)
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
if not session: # 如果檢視函式放了,不為空 session['name']='lqz'
if session.modified: #
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
return
if session.accessed:
response.vary.add("Cookie")
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
# 序列化---》加密了
val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore
# 三段:
response.set_cookie(
name, # session
val, # 三段:
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
# 總結:session的執行流程
1 請求來的時候,會執行open_session--->取出cookie,判斷是否為空,如果不為空,把它反序列化,解密---》字典---》轉到session物件中----》檢視函式
2 請求走的時候,會執行save_session---->把session轉成字典----》序列化加密--》三段---》放到cookie中
4. 閃現
# flash 翻譯過來叫閃現
# 作用:
訪問a頁面,出了錯,重定向到了b頁面,要在b頁面線上a頁面的錯誤資訊
在某個請求中放入值,另一個請求中取出,取出來後就沒了
# 使用
設定值:
flash('不好意思,沒有許可權看')
可以用多次
取值:取出列表
get_flashed_messages()
# 使用方式二:分類設定和獲取
設定值:
flash('錢錢錢',category='lqz')
flash('666',category='c1')')
可以用多次
取值:取出列表
errors = get_flashed_messages(category_filter=['lqz'])
# djagno中有同樣的,message 框架 研究一下,用一用
5. 補充非同步
# 非同步框架 FastAPi
async def index():
print('sdfasd')
a++
await xxx # io操作
async def goods():
pass
# 框架之前的web框架,開啟程序,執行緒---》一條執行緒會執行多個協程函式----》協程函式中遇到io,讀到await關鍵字,就會切換到別的協程函式
# 一旦使用了非同步,以後所有的模組,都要是非同步
-pymysql :同步的
-redis :同步
-aiomysql:非同步
-aioredis:非同步
-在fastapi或sanic中,要操作mysql,redis要使用非同步的框架,否則效率更低
-django 3.x 以後頁支援async 關鍵字
-沒有一個特別好非同步的orm框架
-sqlalchemy在做
-tortoise-orm
https://tortoise-orm.readthedocs.io/en/latest/index.html
# aiomysql
import asyncio
import aiomysql
loop = asyncio.get_event_loop()
async def test_example():
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
user='root', password='', db='mysql',
loop=loop)
cur = await conn.cursor()
await cur.execute("SELECT Host,User FROM user")
print(cur.description)
r = await cur.fetchall()
print(r)
await cur.close()
conn.close()
loop.run_until_complete(test_example())
# aioredis
import aioredis
import asyncio
class Redis:
_redis = None
async def get_redis_pool(self, *args, **kwargs):
if not self._redis:
self._redis = await aioredis.create_redis_pool(*args, **kwargs)
return self._redis
async def close(self):
if self._redis:
self._redis.close()
await self._redis.wait_closed()
async def get_value(key):
redis = Redis()
r = await redis.get_redis_pool(('127.0.0.1', 6379), db=7, encoding='utf-8')
value = await r.get(key)
print(f'{key!r}: {value!r}')
await redis.close()
if __name__ == '__main__':
asyncio.run(get_value('key')) # need python3.7
6. 請求擴充套件
# 在請求進入檢視函式之前,執行一些程式碼
# 請求出了檢視函式以後,執行一些程式碼
# 類似於django的中介軟體完成的功能
# 7個裝飾器
# 1 before_request:在請求進檢視函式之前執行
多個的話,會從上往下,依次執行, django:process_request
如果返回四件套之一,就直接返回了
在這裡面,正常使用request物件
#2 after_request:在請求從檢視函式走之後執行
多個的話,會從下往上,依次執行, django:process_response一樣
要有引數,和返回值,引數就是response物件,返回值也必須是resposne物件
session,request 照常使用
向響應頭寫東西?向cookie中寫東西
# 3 before_first_request:專案啟動後,第一次訪問會執行,以後再也不執行了
可以做一些初始化的操作
# 4 teardown_request:每一個請求之後繫結一個函式,即使遇到了異常,每個請求走,都會執行,記錄錯誤日誌
@app.teardown_request
def tear_down(e):
print(e) # 如果有異常,這是異常物件
print('我執行了')
#5 errorhandler路徑不存在時404,伺服器內部錯誤500
# @app.errorhandler(404)
# def error_404(arg):
# print('404會執行我')
# # return "404錯誤了"
# return render_template('404.html')
@app.errorhandler(500) # debug為False請情況下才能看到
def error_500(arg):
print('500會執行我')
return "伺服器內部錯誤"
# 6 template_global 標籤 ,在模板中用 {{sb(1,2)}}
@app.template_global()
def sb(a1, a2):
return a1 + a2
# 7 template_filter過濾器 在模板中用 {{10|db(1,2)}}
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
7. 藍圖
# blueprint:對目錄進行劃分,因為之前所有程式碼都寫在一個py檔案中,後期肯定要分到多個檔案中
# 藍圖就是為了劃分目錄的
# 使用步驟:
-1 在不同的view的py檔案中,定義藍圖
-2 使用app物件,註冊藍圖
-3 使用藍圖,註冊路由,註冊請求擴充套件
# 不用藍圖劃分目錄
# 目錄結構
flask_blueprint
-static # 靜態檔案存放位置
-templates # 模板存放位置
-user.html # 使用者html頁面
-views # 檢視函式的py檔案
-__init__.py # 裡面定義了Flask的app物件
goods.py # 商品相關檢視
user.py # 使用者相關檢視
app.py #啟動檔案
# 藍圖小型專案
flask_blueprint_little # 專案名
-src # 專案程式碼所在路徑
-__init__.py # app物件建立的地方
-templates # 模板
-user.html
-static # 靜態檔案
-views # 檢視函式存放位置
-user.py # 使用者相關檢視
-order.py # 訂單相關檢視
-manage.py # 啟動檔案
# 大型專案
flask_blurprint_big # 專案名字
-src # 專案程式碼所在位置
-__init__.py # src的init,falsk,app例項化
-settings.py # 配置檔案
-admin # 類似於django的admin app
-__init__.py # 藍圖初始化
-template # 模板
-backend.html
-static # 靜態檔案
-xx.jpg
-views.py # 檢視層
-models.py # models層,後期咱們表模型
-api
-__init__.py
-template
-static
-models.py
-views.py
-manage.py # 啟動檔案