1. 程式人生 > 其它 >【Flask】請求與響應,session使用,閃現,非同步,藍圖

【Flask】請求與響應,session使用,閃現,非同步,藍圖

目錄

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  # 啟動檔案