一、工作原理
在 Flask 中,所有客戶端請求的數據都通過全局的 request
對象訪問。該對象是 請求上下文 的一部分,僅在請求處理期間存在。Flask 在收到請求時自動創建 request
對象,并根據請求類型(如 GET、POST)和內容類型(如表單、JSON)解析數據,將不同來源的數據封裝到對應的屬性中(如 args
、form
、json
)。
二、常用方法
-
查詢參數(URL參數)
使用request.args
(類型:ImmutableMultiDict
)獲取 URL 中的查詢參數。name = request.args.get('name') # 獲取單個參數 all_args = request.args.to_dict() # 轉為字典
-
表單數據
針對application/x-www-form-urlencoded
或multipart/form-data
類型的 POST 請求,使用request.form
。username = request.form.get('username')
-
JSON 數據
當請求的Content-Type
為application/json
時,使用request.json
直接獲取解析后的字典。data = request.json
-
文件上傳
通過request.files
獲取上傳的文件(類型:FileStorage
)。file = request.files.get('file') if file:file.save('uploaded_file.txt')
-
原始數據
使用request.data
獲取未經處理的原始字節數據(如非表單、非JSON的請求體)。 -
請求頭與Cookies
user_agent = request.headers.get('User-Agent') user_token = request.cookies.get('token')
三、高級用法
-
處理多值參數
當參數有多個值時(如多選框),使用getlist
:selected_ids = request.form.getlist('ids')
-
強制解析JSON
即使Content-Type
不是application/json
,也可強制解析:data = request.get_json(force=True)
-
流式處理大文件
使用request.stream
逐塊讀取數據,避免內存溢出:@app.route('/upload', methods=['POST']) def upload():def generate():chunk_size = 4096while True:chunk = request.stream.read(chunk_size)if not chunk:break# 處理chunk...return 'Upload complete'
-
混合數據(表單+JSON)
使用request.values
合并查詢參數和表單數據(不推薦混用,需謹慎處理邏輯)。
四、完整示例
from flask import Flask, request, jsonifyapp = Flask(__name__)@app.route('/api', methods=['GET', 'POST'])
def handle_request():# 獲取查詢參數query_param = request.args.get('q')# 根據不同請求類型處理數據if request.method == 'POST':# 處理表單數據username = request.form.get('username')# 處理JSON數據json_data = request.get_json(silent=True) # 解析失敗返回None# 處理文件上傳uploaded_file = request.files.get('file')if uploaded_file:uploaded_file.save('uploads/' + uploaded_file.filename)return jsonify({"query_param": query_param,"username": username,"json_data": json_data,"file_uploaded": bool(uploaded_file)})else:return jsonify({"query_param": query_param})if __name__ == '__main__':app.run(debug=True)
五、注意事項
-
請求方法影響數據獲取
- GET 請求只有
args
,無form
或files
。 - POST 需根據
Content-Type
選擇正確的屬性(如form
或json
)。
- GET 請求只有
-
處理缺失數據
使用.get('key')
而非['key']
避免KeyError
,可指定默認值:value = request.form.get('key', 'default')
-
JSON解析安全
- 使用
request.get_json(silent=True)
避免解析失敗拋出異常。 - 使用
force=True
時需注意客戶端可能發送非法數據。
- 使用
-
文件上傳安全
- 限制文件類型和大小(通過
MAX_CONTENT_LENGTH
配置)。 - 驗證文件名,避免路徑遍歷漏洞。
- 限制文件類型和大小(通過
六、擴展知識
-
請求鉤子預處理
使用@app.before_request
在請求處理前統一驗證或預處理數據:@app.before_request def check_auth():if not request.endpoint == 'login' and not validate_token(request.headers.get('Token')):return jsonify({"error": "Unauthorized"}), 401
-
第三方庫擴展
- Flask-RESTful:構建 REST API,自動解析請求數據。
- Flask-WTF:集成 WTForms,處理表單驗證和CSRF保護。
-
性能優化
- 對于大文件上傳,使用流式處理或分塊傳輸。
- 啟用
gzip
壓縮減少數據傳輸量。
-
測試請求
使用 Flask 測試客戶端模擬請求:with app.test_client() as client:response = client.post('/api', data={'username': 'test'}, headers={'Content-Type': 'multipart/form-data'})assert response.status_code == 200
七、錯誤處理與調試技巧
1. 優雅處理數據解析錯誤
在解析客戶端數據時,可能會遇到格式錯誤或非法內容,需合理捕獲異常:
@app.route('/parse-json', methods=['POST'])
def parse_json():try:data = request.get_json()if data is None:raise ValueError("Invalid JSON")# 處理數據...except ValueError as e:return jsonify({"error": str(e)}), 400
關鍵點:
- 使用
silent=True
時,即使解析失敗也不會拋出異常,但需手動檢查data
是否為None
。 - 針對文件上傳錯誤,可檢查
request.files
是否存在且文件對象有效。
2. 調試請求數據的實用方法
在開發過程中,快速查看原始請求數據有助于定位問題:
@app.route('/debug', methods=['POST'])
def debug_endpoint():print("Headers:", request.headers)print("Raw Data:", request.data.decode('utf-8'))print("Form Data:", request.form)return "Debug information logged"
工具推薦:
- Postman:模擬復雜請求(如 multipart/form-data 或自定義 headers)。
- curl 命令:快速測試 API 接口:
curl -X POST http://localhost:5000/api -H "Content-Type: application/json" -d '{"key": "value"}'
八、安全加固策略
1. 防范常見攻擊
-
CSRF 保護:使用
Flask-WTF
擴展自動生成和驗證 CSRF Token:from flask_wtf.csrf import CSRFProtect csrf = CSRFProtect(app)
在表單中添加隱藏字段:
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
-
SQL 注入防護:始終使用 ORM(如 SQLAlchemy)或參數化查詢,避免拼接 SQL 字符串。
-
XSS 防護:對用戶輸入的內容進行轉義(Flask 模板默認自動轉義)。
2. 文件上傳安全實踐
-
限制文件擴展名:
allowed_extensions = {'png', 'jpg', 'jpeg'} filename = uploaded_file.filename if '.' not in filename or filename.split('.')[-1].lower() not in allowed_extensions:return "Invalid file type", 400
-
防止路徑遍歷:使用
secure_filename
處理文件名:from werkzeug.utils import secure_filename safe_filename = secure_filename(uploaded_file.filename) uploaded_file.save(f'uploads/{safe_filename}')
九、異步與性能優化
1. 異步處理大請求
使用 async/await
處理耗時操作(需 Flask 2.0+ 支持異步視圖):
@app.route('/async-upload', methods=['POST'])
async def async_upload():data = await request.get_data()# 異步處理數據(如寫入數據庫)return "Processing completed"
適用場景:
- 大文件上傳后的后臺處理(如視頻轉碼)。
- 高并發下的非阻塞 IO 操作。
2. 性能調優建議
-
配置請求體大小限制:
app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 限制為100MB
-
啟用壓縮:通過 Nginx 或 GzipMiddleware 壓縮響應數據:
from flask_compress import Compress Compress(app)
十、與其他技術棧集成
1. 結合前端框架處理數據
-
React/Vue 表單提交:確保前端
Content-Type
與后端匹配:// 使用FormData處理文件上傳 const formData = new FormData(); formData.append('file', fileInput.files[0]); fetch('/api/upload', { method: 'POST', body: formData });
-
AJAX 請求處理:Flask 自動解析
application/json
,前端需明確設置 headers:fetch('/api/data', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ key: 'value' }) });
2. 擴展數據格式支持(如 XML)
若需解析 XML 請求,可自定義解析邏輯:
from xml.etree import ElementTree@app.route('/xml', methods=['POST'])
def parse_xml():xml_data = request.dataroot = ElementTree.fromstring(xml_data)value = root.find('key').textreturn jsonify({"value": value})
十一、實戰案例:構建RESTful API
1. 用戶注冊接口
處理混合數據(JSON + 文件頭像上傳):
@app.route('/register', methods=['POST'])
def register():# 解析JSON數據user_data = request.get_json()username = user_data.get('username')# 處理頭像文件avatar = request.files.get('avatar')if avatar:avatar.save(f'avatars/{secure_filename(avatar.filename)}')# 保存用戶到數據庫(偽代碼)save_user(username)return jsonify({"status": "success"})
2. 分頁查詢接口
結合查詢參數與數據過濾:
@app.route('/articles', methods=['GET'])
def get_articles():page = request.args.get('page', 1, type=int)per_page = request.args.get('per_page', 10, type=int)articles = Article.query.paginate(page=page, per_page=per_page)return jsonify({"data": [article.to_dict() for article in articles.items],"total_pages": articles.pages})
十二、總結
Flask 的請求數據獲取機制兼顧靈活性與簡潔性,開發者需根據實際場景選擇合適的方法:
- 基礎場景:直接使用
request.args
、request.form
、request.json
。 - 復雜場景:結合流式處理、異步操作或第三方庫擴展功能。
- 安全優先:始終驗證輸入、限制資源、防范常見攻擊。
通過合理設計數據流和錯誤處理機制,可以構建出高效、健壯的 Web 應用。