0%

Flask 筆記 | 請求物件

在了解 Flask 請求物件之間,必須先了解何謂請求。

HTTP 請求(多簡稱為請求)是瀏覽器或前端程式發送向後端伺服器要求資料的動作。

例如在網址列輸入 https://example.com/hello,就是對伺服器發出一個 GET 請求,要求 /hello 這個路徑的內容。而前端會用以下幾種方式發送請求:

方式 發出請求的方法 備註
使用網址列 直接輸入網址 預設是 GET
超連結 <a> 點擊超連結 GET
表單 <form> 點擊送出按鈕 GET 或 POST
JavaScript (AJAX, Fetch) 用 JS 動態送出請求 支援 CRUD

這些請求到後端後,就會被 Flask 的 request 接住並解析。而常見的請求方法有以下幾種:

方法 用途 說明 常見情境
GET 讀取資料 向伺服器請求一筆資料(不修改伺服器的東西) 讀取文章、打開網頁、查詢資料
POST 建立資料 向伺服器新增資料(像是填寫表單) 註冊、登入、發文、留言
PUT 替換資料 向伺服器完整更新一筆資料 修改整筆使用者資料
PATCH 局部更新 向伺服器部分更新資料 只改一欄,如只修改 email
DELETE 刪除資料 向伺服器刪除指定資源 刪除帳號、移除留言
HEAD 讀取標頭 GET 類似,但只拿回標頭資訊不拿回內容 檢查資源是否存在(例如圖片)
OPTIONS 查詢支援方法 詢問伺服器支援哪些方法(CORS 時常用) 跨來源請求前的預檢請求

基本屬性

在處理使用者送來的 HTTP 請求時,Flask 提供了一個 request 物件來讀取請求的各種資訊。最基本的屬性包含了請求的方法、網址、路徑、通訊協定等,這些資訊通常會在處理請求邏輯的開頭就被用到。

類別 屬性 說明 舉例
請求基本資訊 method 請求方法,如 GET、POST "POST"
url 完整請求網址 "<http://localhost:5000/form?name=David>"
path 路徑部分 "/form"
scheme 協定 http or https "http"
host 主機名稱 "localhost:5000"
remote_addr 發出請求的 IP "127.0.0.1"
查詢參數 args URL 查詢字串(只能用在 GET) /search?q=flaskrequest.args['q']
表單資料 form POST 表單傳來的資料 <form> 的欄位值
上傳檔案 files 使用者上傳的檔案 request.files['file']
JSON 資料 json 發送的 JSON 主體資料 用 JS fetch(..., body: JSON.stringify(...))
請求標頭 headers 使用者裝置、語言等資訊 request.headers['User-Agent']
Cookie cookies 使用者的 cookie 值 request.cookies['session_id']
重導前 URL referrer 上一頁網址 用來知道用戶從哪裡來
請求類型 content_type 資料格式 "application/json"
請求資料長度 content_length 請求資料長度(位元組) 例如 284
環境資訊 environ 更底層的 WSGI 環境資料 少用,但可 debug

使用 request 物件前,需要在程式碼開頭模組:

1
from flask import request

接著就可以使用物件的屬性與方法。為了顯式觀察 request 物件的屬性,我們使用 logging 模組,並搭配 loggig.debug() 印出請求物件的一些內容。

1
2
3
import logging

logging.basicConfig(level=logging.DEBUG) # 設定 logging 預設層級

基本資訊

request 最基本的幾個屬性,包括請求方法、通訊協定、主機名稱、路徑與完整網址,使用方式是 request.屬性名稱

1
2
3
4
5
6
7
8
@app.route("/")
def index():
logging.debug(f"請求方法: {request.method}")
logging.debug(f"通訊協定: {request.scheme}")
logging.debug(f"主機名稱: {request.host}")
logging.debug(f"路徑: {request.path}")
logging.debug(f"完整網址: {request.url}")
return

執行 app.py 並訪問 / 後,便可在終端機看到以下輸出:

1
2
3
4
5
DEBUG:root:請求方法: GET
DEBUG:root:通訊協定: http
DEBUG:root:主機名稱: 127.0.0.1:5000
DEBUG:root:路徑: /
DEBUG:root:完整網址: http://127.0.0.1:5000/

其實不難發現,這些屬性都與網址息息相關。

標頭 (Header)

當前端發送請求到伺服器時,除了主體資料(像是表單或 JSON),還會附帶一份額外的附註說明,這份附註就叫做請求標頭(Request Headers)。這些資訊可有可無,但如果有了標頭的這些額外資訊,對於後端處理資料會很有幫助

送資料給別人前,信封上寫的一些說明:「我是誰、我講什麼語言、這份資料是什麼格式、我是從哪裡來的」。

標頭名稱 說明 範例值
User-Agent 使用者的裝置與瀏覽器資訊 Mozilla/5.0 (Macintosh...)
Host 你要連線的主機名稱 example.com
Accept 你希望伺服器回傳哪種格式 text/html, application/json
Content-Type 你送出的資料格式 application/json
Referrer 你是從哪個頁面點進來的 https://google.com
Authorization 驗證用的權杖或登入資訊 Bearer <token>
Accept-Language 使用者偏好的語言 zh-TW, en-US

在 Flask 裡,使用 request.headers 這個屬性就能拿到所有的標頭資訊。

1
2
3
4
5
6
@app.route("/")
def index():
logging.debug(f"瀏覽器與作業系統: {request.headers.get('user-agent')}")
logging.debug(f"語言偏好: {request.headers.get('accept-language')}")
logging.debug(f"引薦網址: {request.headers.get('referrer')}")
return

可以得到以下結果

1
2
3
DEBUG:root:瀏覽器與作業系統: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15
DEBUG:root:語言偏好: zh-TW,zh-Hant;q=0.9
DEBUG:root:引薦網址: None

語言代碼格式

基本語言代碼會長這樣:

1
zh-TW, zh;q=0.9, en-US;q=0.8, en;q=0.7

這些是語言地區碼優先權數值(q 值)。可以把它想成是一份語言排行榜,由高到低。而 q 值是 quality value 的縮寫,用來表示語言的優先程度,範圍是 0.0 ~ 1.0,預設是 1.0(也就是不寫 q= 時的意思)。

項目解釋
zh-TW使用者最希望看到「繁體中文(台灣)」的內容
zh;q=0.9如果找不到 zh-TW,就退而求其次選擇「中文」任何版本
en-US;q=0.8如果還找不到中文版本,再選「美式英文」
en;q=0.7最後可以接受任意英文

例如 chromium 瀏覽器可以透過設定修改語言偏好,以 Edge 瀏覽器為例,進入 edge://settings/languages 後,即可看到語言偏好的相關設定:

語言偏好設定

圖:語言偏好設定

利用語言代碼,我們可以進行一些操作。例如語言偏好開頭為 en 時,網頁上就顯示英文的內容,若為 zh 則顯示中文。

1
2
3
4
5
6
7
8
@app.route("/")
def index():
lang = request.headers.get('accept-language')

if lang.startswith("en"):
return "Hello, Flask"
else:
return "哈囉,Flask"