1. 程式人生 > 實用技巧 >02.flask應用基本結構

02.flask應用基本結構

  1. 初始化

所有的Flask程式都必須建立一個程式例項, 這個程式例項就是Flask類的物件。客戶端把請求傳送給Web伺服器, 伺服器再把請求傳送給Flask程式例項, 然後由程式例項處理請求。

建立程式例項:

    from flask import Flask
    app = Flask(__name__)

此處的__name__是一個全域性變數, 它的值是程式碼所處的模組或包的名字, Flask用這個引數決定程式的根目錄, 以便稍後能找到相對於程式根目錄的資原始檔位置。

2.路由和檢視函式

客戶端把請求傳送給Web伺服器, 伺服器再把請求傳送給Flask程式例項, 然後由Flask程式例項處理請求。

程式例項如何處理請求, 答案是程式例項通過路由來處理請求——路由就是URL和處理請求的函式的對映——處理請求的函式就叫做檢視函式。

Flask定義路由最簡便的方式, 是使用程式例項提供的app.route修飾器:

    @app.route('/'):
    def index():
      return '<h1>Hello world!<h1>'

前例把index()函式註冊為程式根地址的處理程式。 (如果部署程式的伺服器域名為www.example.com, 在瀏覽器中訪問http://www.example.com後, 會觸發伺服器執行index()函式。 )

這個函式的返回值稱為響應, 是客戶端接收到的內容。

地址中包含可變部分的路由:

    @app.route('/user/<name>')
    def user(name):
      return '<h1>Hello, %s!</h1>' %name

尖括號中的內容就是動態部分,任何能匹配靜態部分的URL都會對映到這個檢視函式, 呼叫檢視函式時, Flask會將動態部分作為引數傳入函式。

注意:路由中的動態部分預設型別是字串, 不過也可以使用別的型別如:/user/<int: id>只會匹配動態片段id為整數的url。

3.啟動伺服器

Flask 應用自帶 Web 開發伺服器,通過 flask run 命令啟動。這個命令在 FLASK_APP 環境變數指定的 Python 指令碼中尋找應用例項。

Linux 和 macOS 使用者執行下述命令啟動 Web 伺服器:

(venv) $ export FLASK_APP=app.py
(venv) $ flask run
 * Serving Flask app "hello"
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

微軟 Windows 使用者執行的命令和剛才一樣,只不過設定 FLASK_APP 環境變數的方式不同:

(venv) $ set FLASK_APP=app.py
(venv) $ flask run
 * Serving Flask app "hello"
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

伺服器啟動後便開始輪詢,處理請求。直到按 Ctrl+C 鍵停止伺服器,輪詢才會停止。

伺服器執行時,在 Web 瀏覽器的位址列中輸入 http://localhost:5000/。你看到的頁面如圖 2-1 所示。

Flask Web 開發伺服器也可以通過程式設計的方式啟動:呼叫 app.run() 方法。

    if __name__ == '__main__':
      app.run(debug=True) #debug引數為True, 表示啟用除錯模式。

命令列選項

flask 命令支援一些選項。執行 flask --help,或者執行 flask 而不提供任何引數,可以檢視哪些選項可用:

(venv) $ flask --help
Usage: flask [OPTIONS] COMMAND [ARGS]...

  This shell command acts as general utility script for Flask applications.

  It loads the application configured (through the FLASK_APP environment
  variable) and then provides commands either provided by the application or
  Flask itself.

  The most useful commands are the "run" and "shell" command.

  Example usage:

    $ export FLASK_APP=hello.py
    $ export FLASK_DEBUG=1
    $ flask run

Options:
  --version  Show the flask version
  --help     Show this message and exit.

Commands:
  run     Runs a development server.
  shell   Runs a shell in the app context.

flask shell 命令在應用的上下文中開啟一個 Python shell 會話。在這個會話中可以執行維護任務或測試,也可以除錯問題。幾章之後將舉例說明這個命令的用途。

flask run 命令我們已經用過,從名稱可以看出,它的作用是在 Web 開發伺服器中執行應用。這個命令有多個引數:

(venv) $ flask run --help
Usage: flask run [OPTIONS]

  Runs a local development server for the Flask application.

  This local server is recommended for development purposes only but it can
  also be used for simple intranet deployments.  By default it will not
  support any sort of concurrency at all to simplify debugging.  This can be
  changed with the --with-threads option which will enable basic
  multithreading.

  The reloader and debugger are by default enabled if the debug flag of
  Flask is enabled and disabled otherwise.

Options:
  -h, --host TEXT                 The interface to bind to.
  -p, --port INTEGER              The port to bind to.
  --reload / --no-reload          Enable or disable the reloader.  By default
                                  the reloader is active if debug is enabled.
  --debugger / --no-debugger      Enable or disable the debugger.  By default
                                  the debugger is active if debug is enabled.
  --eager-loading / --lazy-loader
                                  Enable or disable eager loading.  By default
                                  eager loading is enabled if the reloader is
                                  disabled.
  --with-threads / --without-threads
                                  Enable or disable multithreading.
  --help                          Show this message and exit.

--host 引數特別有用,它告訴 Web 伺服器在哪個網路介面上監聽客戶端發來的連線。預設情況下,Flask 的 Web 開發伺服器監聽 localhost 上的連線,因此伺服器只接受執行伺服器的計算機發送的連線。下述命令讓 Web 伺服器監聽公共網路介面上的連線,因此同一網路中的其他計算機發送的連線也能接收到:

(venv) $ flask run --host 0.0.0.0
 * Serving Flask app "hello"
 * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

現在,網路中的任何計算機都能通過 http://a.b.c.d:5000 訪問 Web 伺服器。其中,a.b.c.d 是執行伺服器的計算機的 IP 地址。

請求–響應迴圈

應用和請求上下文

Flask 從客戶端收到請求時,要讓檢視函式能訪問一些物件,這樣才能處理請求。請求物件就是一個很好的例子,它封裝了客戶端傳送的 HTTP 請求。

為了避免大量可有可無的引數把檢視函式弄得一團糟,Flask 使用上下文臨時把某些物件變為全域性可訪問。有了上下文,便可以像下面這樣編寫檢視函式:

from flask import request

@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')
    return '<p>Your browser is {}</p>'.format(user_agent)

請求分派

應用收到客戶端發來的請求時,要找到處理該請求的檢視函式。為了完成這個任務,Flask 會在應用的 URL 對映中查詢請求的 URL。URL 對映是 URL 和檢視函式之間的對應關係。Flask 使用 app.route 裝飾器構建對映。

要想檢視 Flask 應用中的 URL 對映是什麼樣子,可以在 Python shell 中審查為 app.py 生成的對映。測試之前,請確保你激活了虛擬環境:

(venv) $ python
>>> from app import app
>>> app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
 <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
 <Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])

/ 和 /user/ 路由在應用中使用 app.route 裝飾器定義。/static/ 路由是 Flask 新增的特殊路由,用於訪問靜態檔案。

URL 對映中的 (HEAD, OPTIONS, GET) 是請求方法,由路由進行處理。HTTP 規範中規定,每個請求都有對應的處理方法,這通常表示客戶端想讓伺服器執行什麼樣的操作。Flask 為每個路由都指定了請求方法,這樣即使不同的請求方法傳送到相同的 URL 上時,也會使用不同的檢視函式處理。HEAD 和 OPTIONS 方法由 Flask 自動處理。

響應

Flask 呼叫檢視函式後,會將其返回值作為響應的內容。多數情況下,響應就是一個簡單的字串,作為 HTML 頁面回送客戶端。

但 HTTP 協議需要的不僅是作為請求響應的字串。HTTP 響應中一個很重要的部分是狀態碼,Flask 預設設為 200,表明請求已被成功處理。

如果檢視函式返回的響應需要使用不同的狀態碼,可以把數字程式碼作為第二個返回值,新增到響應文字之後。例如,下述檢視函式返回 400 狀態碼,表示請求無效:

@app.route('/')
def index():
    return '<h1>Bad Request</h1>', 400

如果不想返回由 1 個、2 個或 3 個值組成的元組,Flask 檢視函式還可以返回一個響應物件。make_response() 函式可接受 1 個、2 個或 3 個引數(和檢視函式的返回值一樣),然後返回一個等效的響應物件。有時我們需要在檢視函式中生成響應物件,然後在響應物件上呼叫各個方法,進一步設定響應。下例建立一個響應物件,然後設定 cookie:

from flask import make_response

@app.route('/')
def index():
    response = make_response('<h1>This document carries a cookie!</h1>')
    response.set_cookie('answer', '42')
    return response

響應有個特殊的型別,稱為重定向。這種響應沒有頁面文件,只會告訴瀏覽器一個新 URL,用以載入新頁面。

重定向的狀態碼通常是 302,在 Location 首部中提供目標 URL。

from flask import redirect

@app.route('/')
def index():
    return redirect('http://www.example.com')

還有一種特殊的響應由 abort() 函式生成,用於處理錯誤。在下面這個例子中,如果 URL 中動態引數 id 對應的使用者不存在,就返回狀態碼 404:

from flask import abort

@app.route('/user/<id>')
def get_user(id):
    user = load_user(id)
    if not user:
        abort(404)
    return '<h1>Hello, {}</h1>'.format(user.name)

注意,abort() 不會把控制權交還給呼叫它的函式,而是丟擲異常。