Flask-入門系列教程(二)_第1頁(yè)
Flask-入門系列教程(二)_第2頁(yè)
Flask-入門系列教程(二)_第3頁(yè)
Flask-入門系列教程(二)_第4頁(yè)
Flask-入門系列教程(二)_第5頁(yè)
已閱讀5頁(yè),還剩2頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

請(qǐng)求響應(yīng)循環(huán)其實(shí)大家對(duì)于HTTP協(xié)議應(yīng)該是再熟悉不過(guò)了,它是超文本傳輸協(xié)議,定義了服務(wù)器和客戶端之間信息交流的格式和傳遞方式。那么對(duì)于上面的問(wèn)題,我們其實(shí)也可以大致的說(shuō)出一個(gè)簡(jiǎn)易流程:按下Enter之后,瀏覽器會(huì)向URL地址發(fā)送一個(gè)HTTP請(qǐng)求在瀏覽器的背后,有一個(gè)后臺(tái)程序,用于接收相關(guān)請(qǐng)求,并返回處理的結(jié)果瀏覽器接收結(jié)果,并渲染給終端用戶查看事實(shí)上,每一個(gè)Web應(yīng)用都包含這種處理模式,即“請(qǐng)求-響應(yīng)循環(huán)(Request-ResponseCycle)”:客戶端(瀏覽器等)發(fā)出請(qǐng)求,服務(wù)端處理請(qǐng)求并響應(yīng)。我們?cè)侔焉厦娴牧鞒虜U(kuò)展到Flask服務(wù)器上,就是由瀏覽器生成的HTTP請(qǐng)求發(fā)送至Web服務(wù)器。Web服務(wù)器接收到請(qǐng)求后,經(jīng)由WSGI協(xié)議把數(shù)據(jù)轉(zhuǎn)換成Flask程序能夠識(shí)別的數(shù)據(jù)后,傳遞給Flask程序。然后Flask程序再根據(jù)視圖函數(shù)等處理相關(guān)請(qǐng)求,最后再返回響應(yīng)給Web服務(wù)器。最終交由瀏覽器來(lái)渲染結(jié)果,比如加載CSS,執(zhí)行JavaScript代碼等等操作。我們可以看下下面的圖片這里有兩個(gè)概念我們要先明確下Web服務(wù)器:Web服務(wù)器是一類特殊的服務(wù)器,其作用是主要是接收HTTP請(qǐng)求并返回響應(yīng)。我們常用的Web服務(wù)器有Nginx,tomcat等,相信大家都非常熟悉或多少聽(tīng)說(shuō)些。WSGI:它確切來(lái)說(shuō)應(yīng)該是一種協(xié)議,或者接口規(guī)范。定義了web服務(wù)器和web應(yīng)用(Flask等)之間的接口規(guī)范。只有Web服務(wù)器和Web應(yīng)用都遵守了WSGI協(xié)議,那么他們才能正常通信。比如說(shuō)在上一節(jié)我們使用app.run()啟動(dòng)測(cè)試服務(wù)器時(shí),就是使用了Flask自帶的Web服務(wù)器,當(dāng)然這種服務(wù)器只能用來(lái)開發(fā)測(cè)試時(shí)使用,在生成環(huán)境,我們需要部署到Nginx等Web服務(wù)器上。在了解了Web程序的整體運(yùn)行流程之后,我們?cè)賮?lái)深入的探究下Flask的工作原理。Flask上下文HTTP請(qǐng)求當(dāng)Flask接收到客戶端的請(qǐng)求后(后面的章節(jié)中我們都會(huì)直接省略Web服務(wù)器和WSGI的轉(zhuǎn)換步驟),就會(huì)產(chǎn)生一些視圖函數(shù)可以訪問(wèn)的對(duì)象,通過(guò)這些對(duì)象來(lái)處理請(qǐng)求,這就是請(qǐng)求對(duì)象--request。request對(duì)象包含了HTTP請(qǐng)求中的URL信息和相關(guān)的報(bào)文信息URL信息例如請(qǐng)求URL為:xxxx://xxx.xxxxxxxi.xxx/hello?name=xxxxx屬性值path'/hello'full_path'/hello?name=xxxxx'host'xxx.xxxxxxxxi.top'host_url'xxxx://xxx.xxxxxxxx.top'base_url'xxxx://www.xxxxxx.top/hello'url'xxxx://xxx.xxxxxxxi.xxx/hello?name=xxxxx'報(bào)文信息屬性或方法說(shuō)明args查詢字符串信息cookiescookies信息字典data字符串形式的請(qǐng)求數(shù)據(jù)form表單數(shù)據(jù)get_json()獲取json類型的請(qǐng)求數(shù)據(jù)method請(qǐng)求的HTTP方法下面我們通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)具體查看下@app.route('/test/')

def

test_view():

query

=

'Flask'

if

request.args:

query

=

request.args.get('name',

'Flask')

host

=

request.host

path

=

request.full_path

cookie

=

request.cookies

method

=

request.method

return

"""

<h1>

<p>query

string:

%s</p>

<p>host:

%s</p>

<p>path:

%s</p>

<p>cookies:

%s</p>

<p>method:

%s</p>

</h1>

"""

%

(query,

host,

path,

cookie,

method)當(dāng)我們?cè)跒g覽器輸入:xxxx://xxx.0.0.1:5000/test/,可以得到當(dāng)我們?cè)跒g覽器輸入:xxxx://xxx.0.0.1:5000/test/?name=luobo,可以得到在這里,request是一個(gè)全局的變量,我們可以在任何的視圖函數(shù)中去使用它。當(dāng)然,這僅僅局限在當(dāng)前線程中,對(duì)于多線程服務(wù)器中,不同線程服務(wù)器的請(qǐng)求對(duì)象是不同的。兩種上下文在Flask中,有兩種上下文:程序上下文和請(qǐng)求上下文。主要包括下面四種變量名上下文類型說(shuō)明request請(qǐng)求上下文請(qǐng)求對(duì)象,封裝了HTTP請(qǐng)求中的內(nèi)容session請(qǐng)求上下文請(qǐng)求上下文用戶會(huì)話,存儲(chǔ)請(qǐng)求之間需要保留的值g程序上下文處理請(qǐng)求時(shí)的臨時(shí)存儲(chǔ)對(duì)象,僅在當(dāng)前請(qǐng)求有效current_app程序上下文當(dāng)前的程序?qū)嵗龑?duì)于request,我們已經(jīng)了解了,下面再來(lái)看看session。sessionsession最常用的就是確認(rèn)用戶狀態(tài)了,比如檢查用戶是否登陸等。下面我們就簡(jiǎn)單實(shí)現(xiàn)一個(gè)基于瀏覽器的用戶認(rèn)證功能,來(lái)理解下session的強(qiáng)大功效。普通的認(rèn)證系統(tǒng),用戶在頁(yè)面表單中輸入用戶名和密碼后,后臺(tái)程序進(jìn)行確認(rèn),如果認(rèn)證通過(guò),則返回響應(yīng),并在瀏覽器的Cookie中設(shè)入標(biāo)記,例如“l(fā)oginID:User1”。但是因?yàn)闉g覽器Cookie是很容易被修改的,所以如果使用名稱存儲(chǔ)這些信息就會(huì)非常不安全,此時(shí)就需要session登場(chǎng)了。在Flask中session通過(guò)密鑰對(duì)數(shù)據(jù)進(jìn)行簽名從而加密數(shù)據(jù),所以我們需要先設(shè)置一個(gè)密鑰。app.secret_key

=

'Very

Hard

Secret'當(dāng)然,更加安全的做法是把該密鑰寫到部署服務(wù)器的環(huán)境變量中,對(duì)于這種寫法,我們?cè)诤竺娌渴鸪绦驎r(shí)再詳細(xì)講解。

接下來(lái)我們做模擬用戶認(rèn)證的情況,寫兩個(gè)視圖函數(shù),分別模擬登陸和登出場(chǎng)景。@app.route('/login/')

def

login():

session['loginID']

=

'admin'

return

redirect(url_for('welcome'))@app.route('/logout/')

def

logout():

if

'loginID'

in

session:

session.pop('loginID')

return

redirect(url_for('welcome'))再修改welcome視圖函數(shù),用于展示是否登陸@app.route('/user/',

defaults={'name':

'陌生人'})

@app.route('/user/<name>')

def

welcome(name):

res

=

'<h1>Hello,

%s!</h1>'

%

name

if

'loginID'

in

session:

res

+=

'Authenticated'

else:

res

+=

'UnAuthenticated'

return

res這里我們使用了redirect函數(shù),是一個(gè)重定向方法。只需要傳入目標(biāo)的URL地址,就可以在視圖函數(shù)處理結(jié)束后跳轉(zhuǎn)至目標(biāo)的頁(yè)面。當(dāng)我在瀏覽器輸入:xxxx://xxx.0.0.1:5000/login/的時(shí)候,就會(huì)在瀏覽器中插入一個(gè)加密的cookie并跳轉(zhuǎn)至welcome頁(yè)面可以看到,插入的cookie是加密的,這樣就加大了攻擊者的攻擊難度,從而在一定程度上保護(hù)了我們系統(tǒng)的安全。g和current_app其實(shí)你應(yīng)該會(huì)有個(gè)疑惑,我們已經(jīng)有了一個(gè)app程序?qū)嵗耍瑸槭裁催€需要定義一個(gè)current_app變量呢?在不同的視圖函數(shù)中,request對(duì)象都表示和視圖函數(shù)對(duì)應(yīng)的請(qǐng)求,也就是當(dāng)前請(qǐng)求(currentrequest)。而程序會(huì)有多個(gè)程序?qū)嵗那闆r,為了能獲取對(duì)應(yīng)的程序?qū)嵗?,而不是固定的某一個(gè)程序?qū)嵗?,我們就需要使用current_app變量。當(dāng)然對(duì)于多個(gè)程序?qū)嵗那闆r,我們留待后面的章節(jié)詳細(xì)介紹。g存儲(chǔ)在程序上下文中,而程序上下文會(huì)隨著每一個(gè)請(qǐng)求的進(jìn)入而激活,隨著每一個(gè)請(qǐng)求的處理完畢而銷毀,所以每次請(qǐng)求都會(huì)重設(shè)這個(gè)值。比如說(shuō)如果對(duì)于某個(gè)請(qǐng)求,我們幾個(gè)視圖函數(shù)都需要用到一個(gè)前端傳遞過(guò)來(lái)的變量,那么就可以把它保存到g變量當(dāng)中

=

request.args.get('name')這樣,其他的視圖函數(shù)就可以在同一個(gè)請(qǐng)求中直接使用來(lái)訪問(wèn),而不用每次都調(diào)用request了。

對(duì)于current_app和g的更多使用方式,在后面的學(xué)習(xí)中我們會(huì)慢慢接觸的更多。請(qǐng)求鉤子在處理請(qǐng)求之前或之后執(zhí)行的代碼,就稱為請(qǐng)求鉤子。比如在請(qǐng)求之前,我們需要初始化數(shù)據(jù)庫(kù),創(chuàng)建admin用戶等等,就需要在請(qǐng)求之前調(diào)用請(qǐng)求鉤子來(lái)做這件事情。在Flask中提供了四種請(qǐng)求鉤子,以裝飾器的形式注冊(cè)到函數(shù),使得我們可以方便的應(yīng)用該功能.鉤子名稱作用before_first_request在處理第一個(gè)請(qǐng)求之前運(yùn)行before_request在每次請(qǐng)求之前運(yùn)行after_request如果沒(méi)有未處理的異常拋出,則在每次請(qǐng)求之后運(yùn)行teardown_request即使有未處理的異常拋出,也在每次請(qǐng)求之后運(yùn)行在請(qǐng)求鉤子函數(shù)和視圖函數(shù)之間共享數(shù)據(jù)一般使用上下文全局變量g,比如上面的例子我們就可以寫成from

flask

import

g

@app.before_request

def

get_name():

=

request.args.get('name')重定向回上一個(gè)頁(yè)面功能實(shí)現(xiàn)重定向回上一個(gè)頁(yè)面,這應(yīng)該是一個(gè)非常常見(jiàn)的應(yīng)用場(chǎng)景,那么該如何通過(guò)Flask來(lái)實(shí)現(xiàn)呢。首先我們修改下login視圖函數(shù),在請(qǐng)求參數(shù)中查找next參數(shù),如果存在則重定向到next參數(shù)對(duì)應(yīng)的地址,否則重定向到hello視圖函數(shù)對(duì)應(yīng)的地址@app.route('/login/')

def

login():

session['loginID']

=

'admin'

return

redirect(request.args.get('next')

or

url_for('hello'))這里所謂的next參數(shù),其實(shí)只是一種約定俗成的命名方式再修改needpage1視圖函數(shù),如果用戶未登陸則展示登陸鏈接,并保存next參數(shù)@app.route('/needlogin1/')

def

needLogin1():

if

'loginID'

in

session:

return

'<h1>Hello,

needLogin1!</h1>'

else:

return

"""

<h1>Login</h1><a

href="%s">Go

To

Login</a>

"""

%

url_for('login',

next=request.url)這樣,當(dāng)用戶處于未登錄狀態(tài)時(shí),就可以點(diǎn)擊GoToLogin鏈接進(jìn)行登陸,登陸成功之后會(huì)自動(dòng)跳轉(zhuǎn)回當(dāng)前頁(yè)面了。安全處理現(xiàn)在我們雖然完成了功能,但是卻還遺留了相關(guān)的安全問(wèn)題。因?yàn)槲覀兊膎ext參數(shù)是以查詢字符串的方式寫在URL里的,所以如果有人攔截了我們的請(qǐng)求,就可以隨便修改next的指向,此時(shí)我們就需要驗(yàn)證next變量是否屬于我們的應(yīng)用,否則很容易被指向外部鏈接,從而造成安全隱患。我們先創(chuàng)建一個(gè)檢查URL正確性的函數(shù)from

urllib.parse

import

urlparse

def

check_next(target):

ref_url

=

urlparse(request.host_url)

test_url

=

urlparse(target)

return

ref_loc

==

test_loc該函數(shù)接收目標(biāo)地址為參數(shù),并比較本應(yīng)用的host_url和目標(biāo)地址的host_url是否相同

改寫login視圖函數(shù)@app.route('/login/')

def

login():

session['loginID']

=

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論