使用Web框架
瞭解了WSGI框架,我們發現,其實一個Web APP,就是寫一個WSGI處理函數,針對每一個HTTP請求響應。
但是如何處理HTTP請求不是問題,問題是如何同時處理100個不同URL。
每一個URL可以對應GET和POST請求,當然還有DELETE、PUT等請求,但是我們通常只考慮GET和POST請求。
一個最簡單的想法是從environ中取出HTTP請求,然後逐個判斷:
def application(environ,start_response):
method =environ('REQUEST_METHOD')
path =environ('PATH_INFO')
if method =='GET' and path =='/':
return handle_home(environ,start_response)
if method =='POST' and path =='/signin':
return handle_signin(environ,start_response)
只是這樣寫下去,代碼就無法維護了。
原因是WSGI提供的接口雖然比HTTP高級了很多,但和Web APP處理的邏輯相比,還是比較低級的,我們需要在WSGI之上進一步抽象,讓我們專注用一個函數處理一個URL,至於URL到函數的映射,就交給Web框架來做。
由於用Python開發一個Web框架十分容易,所以Python有上百個開源的Web框架。我們先選擇一個比較流行的Web框架-Flask來使用。
用Flask編寫Web APP比使用WSGI簡單,我們先用pip安裝Flask:
pip install Flask
然後寫一個app.py,處理3個URL,分別是:
GET /:首頁,返回Home;
GET /signin :登陸頁,顯示登陸表單;
POST /signin:處理登陸表單,顯示登陸結果。
注意,同一個URL/signin分別有GET和POST兩種請求,映射到兩個處理函數中。
Flask通過Python的裝飾器在內部自動的把URL和函數關聯起來,所以,我們寫出來的代碼就像這樣:
from flask import Flask
from flask import request
app =Flask(__name__)
@app.route('/',methods =['GET','POST'])
def home():
return <h1>home</h1>
@app.route('/signin',methods =['GET'])
return '''<form action="/signin" method="post">
<p><input name="username"></p>
<p><input name="password" type="password"></p>
<p><button type="submit">Sign In</button></p>
</form>'''
@app.route('/signin', methods=['POST'])
def signin():
# 需要從request對象讀取表單內容:
if request.form['username']=='admin' and request.form['password']=='password':
return '<h3>Hello, admin!</h3>'
return '<h3>Bad username or password.</h3>'
if __name__ == '__main__':
app.run()
運行app.py
python app.py
打開瀏覽器,輸入:http://localhost:5000/
首頁顯示正確。
再次輸入:http://localhost:5000/signin/
輸入預設的admin和密碼password
登陸成功!
輸入其他錯誤的用戶名或密碼:
實際的Web APP 應該拿到用戶名和口令後,去數據庫查詢再對比,來判斷用戶是否能登陸。
除了Flask之外,常見的Python Web框架還有:
Django:全能型Web框架;
web.py:一個小巧的web框架;
Bottle:和Flask類似的框架;
Tornado:FaceBook的開源異步框架。
當然,開發Python Web框架也不是什麼難事,我們後面也會降到Web框架開發內容。
小結:
有了Web框架,我們在編寫Web應用時,注意力就從WSGI處理函數轉移到URL+對應的處理函數u,這樣,編寫Web APP就更簡單了。
在編寫URL處理函數時,除了配置URL外,從HTTP請求拿到用戶數據也是非常重要的。Web框架都提供了自己的API來實現該功能。Flask通過request.form['name']來獲取表單內容。