2.1 從 Hello World 開始
Flask程序運行過程:
所有Flask程序必須有一個程序實例。
Flask調用視圖函數后,會將視圖函數的返回值作為響應的內容,返回給客戶端。一般情況下,響應內容主要是字符串和狀態碼。
當客戶端想要獲取資源時,一般會通過瀏覽器發起HTTP請求。此時,Web服務器使用WSGI(Web Server Gateway Interface)協議,把來自客戶端的所有請求都交給Flask程序實例。WSGI是為 Python 語言定義的Web服務器和Web應用程序之間的一種簡單而通用的接口,它封裝了接受HTTP請求、解析HTTP請求、發送HTTP,響應等等的這些底層的代碼和操作,使開發者可以高效的編寫Web應用。
程序實例使用Werkzeug來做路由分發(URL請求和視圖函數之間的對應關系)。根據每個URL請求,找到具體的視圖函數。 在Flask程序中,路由的實現一般是通過程序實例的route裝飾器實現。route裝飾器內部會調用add_url_route()方法實現路由注冊。
調用視圖函數,獲取響應數據后,把數據傳入HTML模板文件中,模板引擎負責渲染響應數據,然后由Flask返回響應數據給瀏覽器,最后瀏覽器處理返回的結果顯示給客戶端。
示例:
新建文件hello.py:
# 導入Flask類
from flask import Flask#Flask類接收一個參數__name__
app = Flask(__name__)# 裝飾器的作用是將路由映射到視圖函數index
@app.route('/')
def index():return 'Hello World'# Flask應用程序實例的run方法啟動WEB服務器
if __name__ == '__main__':app.run()
查看視圖函數中的路由:
?
給路由傳參示例:
有時我們需要將同一類URL映射到同一個視圖函數處理,比如:使用同一個視圖函數 來顯示不同用戶的個人信息。
# 路由傳遞的參數默認當做string處理,這里指定int,尖括號中冒號后面的內容是動態的
@app.route('/user/<int:id>')
def hello_itcast(id):return 'hello itcast %d' %id
?
返回狀態碼示例:
return后面可以自主定義狀態碼(即使這個狀態碼不存在)。當客戶端的請求已經處理完成,由視圖函數決定返回給客戶端一個狀態碼,告知客戶端這次請求的處理結果。
@app.route('/')
def hello_itcast():return 'hello itcast',999
?
abort函數:
如果在視圖函數執行過程中,出現了異常錯誤,我們可以使用abort函數立即終止視圖函數的執行。通過abort函數,可以向前端返回一個http標準中存在的錯誤狀態碼,表示出現的錯誤信息。
使用abort拋出一個http標準中不存在的自定義的狀態碼,沒有實際意義。如果abort函數被觸發,其后面的語句將不會執行。其類似于python中raise。
from flask import Flask,abort
@app.route('/')
def hello_itcast():abort(404)return 'hello itcast',999
捕獲異常:
在Flask中通過裝飾器來實現捕獲異常,errorhandler()接收的參數為異常狀態碼。視圖函數的參數,返回的是錯誤信息。
@app.errorhandler(404)
def error(e):return '您請求的頁面不存在了,請確認后再次訪問!%s'%e
?
重定向redirect示例
from flask import redirect
@app.route('/')
def hello_itcast():return redirect('http://www.itcast.cn')
?
正則URL示例:
正則URL是為了匹配指定的URL,而匹配指定的URL則可以達到限制訪問,以及優化訪問路徑的目的。
from flask import Flask
from werkzeug.routing import BaseConverterclass Regex_url(BaseConverter):def __init__(self,url_map,*args):super(Regex_url,self).__init__(url_map)self.regex = args[0]app = Flask(__name__)
app.url_map.converters['re'] = Regex_url@app.route('/user/<re("[a-z]{3}"):id>')
def hello_itcast(id):return 'hello %s' %id
設置cookie和獲取cookie
from flask import Flask,make_response
@app.route('/cookie')
def set_cookie():resp = make_response('this is to set cookie')resp.set_cookie('username', 'itcast')return resp
from flask import Flask,request
#獲取cookie
@app.route('/request')
def resp_cookie():resp = request.cookies.get('username')return resp
2.2 擴展
上下文:相當于一個容器,保存了Flask程序運行過程中的一些信息。
Flask中有兩種上下文,請求上下文和應用上下文。
請求上下文(request context)
request和session都屬于請求上下文對象。
request:封裝了HTTP請求的內容,針對的是http請求。舉例:user = request.args.get('user'),獲取的是get請求的參數。
session:用來記錄請求會話中的信息,針對的是用戶信息。舉例:session['name'] = user.id,可以記錄用戶信息。還可以通過session.get('name')獲取用戶信息。
應用上下文(application context)
current_app和g都屬于應用上下文對象。
current_app:表示當前運行程序文件的程序實例。我們可以通過current_app.name打印出當前應用程序實例的名字。
?
g:處理請求時,用于臨時存儲的對象,每次請求都會重設這個變量。比如:我們可以獲取一些臨時請求的用戶信息。
- 當調用app = Flask(_name_)的時候,創建了程序應用對象app;
- request 在每次http請求發生時,WSGI server調用Flask.call();然后在Flask內部創建的request對象;
- app的生命周期大于request和g,一個app存活期間,可能發生多次http請求,所以就會有多個request和g。
- 最終傳入視圖函數,通過return、redirect或render_template生成response對象,返回給客戶端。
區別:?請求上下文:保存了客戶端和服務器交互的數據。 應用上下文:在flask程序運行過程中,保存的一些配置信息,比如程序文件名、數據庫的連接、用戶信息等。
請求鉤子
在客戶端和服務器交互的過程中,有些準備工作或掃尾工作需要處理,比如:在請求開始時,建立數據庫連接;在請求結束時,指定數據的交互格式。為了讓每個視圖函數避免編寫重復功能的代碼,Flask提供了通用設施的功能,即請求鉤子。
請求鉤子是通過裝飾器的形式實現,Flask支持如下四種請求鉤子:
before_first_request:在處理第一個請求前運行。
before_request:在每次請求前運行。
after_request:如果沒有未處理的異常拋出,在每次請求后運行。
teardown_request:在每次請求后運行,即使有未處理的異常拋出。
Flask裝飾器路由的實現:
Flask有兩大核心:Werkzeug和Jinja2。Werkzeug實現路由、調試和Web服務器網關接口。Jinja2實現了模板。
Werkzeug是一個遵循WSGI協議的python函數庫。其內部實現了很多Web框架底層的東西,比如request和response對象;與WSGI規范的兼容;支持Unicode;支持基本的會話管理和簽名Cookie;集成URL請求路由等。
Werkzeug庫的routing模塊負責實現URL解析。不同的URL對應不同的視圖函數,routing模塊會對請求信息的URL進行解析,匹配到URL對應的視圖函數,以此生成一個響應信息。
routing模塊內部有Rule類(用來構造不同的URL模式的對象)、Map類(存儲所有的URL規則)、MapAdapter類(負責具體URL匹配的工作);
Flask-Script擴展命令行
通過使用Flask-Script擴展,我們可以在Flask服務器啟動的時候,通過命令行的方式傳入參數。而不僅僅通過app.run()方法中傳參,比如我們可以通過python hello.py runserver --host ip地址,告訴服務器在哪個網絡接口監聽來自客戶端的連接。默認情況下,服務器只監聽來自服務器所在計算機發起的連接,即localhost連接。
我們可以通過python hello.py runserver --help來查看參數。
from flask import Flask
from flask_script import Managerapp = Flask(__name__)manager = Manager(app)@app.route('/')
def index():return '床前明月光'if __name__ == "__main__":manager.run()
?
?
?