当前位置: 首页 > news >正文

Flask 之 Request 对象详解:全面掌握请求数据处理

在 Flask 框架中,request 是处理客户端请求数据的核心工具。它封装了 HTTP 请求的全部信息,让你能够轻松访问:

  • 查询参数(Query Parameters)
  • 表单数据(Form Data)
  • JSON 载荷(JSON Payload)
  • 文件上传(File Uploads)
  • 请求头(Headers)
  • Cookies
  • 客户端 IP
  • URL 信息

本文将带你系统性地掌握 request 对象的使用技巧,涵盖基础用法、高级特性、安全实践和最佳模式,助你写出更健壮、更安全、更可维护的 Flask 应用。


一、request 对象基础:全局但线程安全

1.1 导入与基本使用

from flask import Flask, requestapp = Flask(__name__)@app.route('/')
def index():return f'请求方法: {request.method}, URL: {request.url}'

📌 关键特性

  • request 是一个 上下文全局对象(Context-local),在每个请求中独立存在。
  • 尽管看起来像全局变量,但它是线程安全的,每个请求都有自己的 request 实例。
  • 只能在视图函数或 @before_request 钩子中使用。

1.2 生命周期与上下文

@app.before_request
def log_request_info():print(f"👉 请求开始: {request.method} {request.url}")@app.route('/hello')
def hello():# request 在此可用return "Hello World!"@app.after_request
def add_header(resp):# 仍可访问 requestresp.headers['X-Request-Method'] = request.methodreturn resp

✅ Flask 使用 Local Proxy 模式实现请求上下文隔离。


二、请求方法与 URL 信息

2.1 常用属性一览

@app.route('/info')
def request_info():return {'method': request.method,           # GET, POST, PUT, DELETE...'url': request.url,                 # 完整URL: https://example.com/info?q=1'base_url': request.base_url,       # 基础URL: https://example.com/info'path': request.path,               # 路径: /info'host': request.host,               # 主机: example.com'scheme': request.scheme,           # 协议: http 或 https'remote_addr': request.remote_addr, # 客户端IP(可能不准确)'full_path': request.full_path,     # 路径+查询: /info?q=1'query_string': request.query_string # 查询字符串: b'q=1'}

2.2 安全获取客户端 IP(处理代理)

def get_client_ip():"""考虑反向代理(如 Nginx)的情况"""x_forwarded_for = request.headers.get('X-Forwarded-For')if x_forwarded_for:# X-Forwarded-For: client, proxy1, proxy2return x_forwarded_for.split(',')[0].strip()x_real_ip = request.headers.get('X-Real-IP')if x_real_ip:return x_real_ipreturn request.remote_addr or 'unknown'@app.route('/ip')
def show_ip():return {'client_ip': get_client_ip()}

✅ 建议在 Nginx 中配置:

深色版本proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

三、查询参数(Query Parameters)

3.1 基本获取

@app.route('/search')
def search():q = request.args.get('q')           # 返回字符串或 Nonepage = request.args.get('page', 1, type=int)  # 默认值 + 类型转换category = request.args.get('category', 'all')return f'搜索: {q}, 页码: {page}, 分类: {category}'

3.2 获取所有参数

@app.route('/params')
def all_params():# 转为字典all_args = request.args.to_dict()# 获取多值参数(如 ?tag=python&tag=web)tags = request.args.getlist('tag')return {'all_params': all_args,'tags': tags}

3.3 参数验证

@app.route('/validate')
def validated_search():query = request.args.get('q', '').strip()if not query:return {'error': '搜索关键词不能为空'}, 400page = request.args.get('page', 1, type=int)if page < 1:page = 1limit = min(request.args.get('limit', 20, type=int), 100)  # 限制最大值return {'query': query, 'page': page, 'limit': limit}

四、表单数据(Form Data)

4.1 处理 HTML 表单

@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':username = request.form['username']  # KeyError if missingpassword = request.form.get('password')  # 返回 None if missingremember = 'remember' in request.form  # 复选框是否选中if not username or not password:return '用户名和密码不能为空', 400# 验证逻辑...return f'欢迎,{username}!'# GET 请求:返回登录页面return '''<form method="post"><input type="text" name="username" placeholder="用户名" required><br><input type="password" name="password" placeholder="密码" required><br><input type="checkbox" name="remember"> 记住我<br><input type="submit" value="登录"></form>'''

4.2 获取所有表单数据

@app.route('/form-data', methods=['POST'])
def form_data():form_dict = request.form.to_dict()hobbies = request.form.getlist('hobbies')  # 多选框return {'form': form_dict,'hobbies': hobbies}

4.3 文件上传处理

import os
from werkzeug.utils import secure_filenameUPLOAD_FOLDER = 'uploads'
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}def allowed_file(filename):return '.' in filename and \filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS@app.route('/upload', methods=['GET', 'POST'])
def upload_file():if request.method == 'POST':if 'file' not in request.files:return '没有文件上传', 400file = request.files['file']if file.filename == '':return '未选择文件', 400if file and allowed_file(file.filename):filename = secure_filename(file.filename)file.save(os.path.join(UPLOAD_FOLDER, filename))return f'文件 {filename} 上传成功!'return '''<form method="post" enctype="multipart/form-data"><input type="file" name="file" required><input type="submit" value="上传"></form>'''

secure_filename() 防止路径遍历攻击。


五、JSON 数据处理(API 开发核心)

5.1 处理 JSON 请求

from flask import jsonify@app.route('/api/user', methods=['POST'])
def create_user():# 检查 Content-Typeif not request.is_json:return {'error': 'Content-Type must be application/json'}, 400# 获取 JSON 数据data = request.get_json()if not data:return {'error': '无效的 JSON 数据'}, 400name = data.get('name')email = data.get('email')age = data.get('age', 0)if not name or not email:return {'error': '姓名和邮箱为必填项'}, 400# 创建用户逻辑...user = save_user_to_db(name, email, age)return jsonify({'message': '用户创建成功','user': user}), 201

5.2 获取原始数据

@app.route('/raw', methods=['POST'])
def raw_data():raw_bytes = request.get_data()# 或stream_data = request.stream.read()return {'length': len(raw_bytes),'type': str(type(raw_bytes)),  # <class 'bytes'>'content': raw_bytes.decode('utf-8', errors='ignore')}

六、请求头(Headers)

6.1 读取请求头

@app.route('/headers')
def show_headers():headers = dict(request.headers)  # 转为普通字典user_agent = request.headers.get('User-Agent')content_type = request.headers.get('Content-Type')auth = request.headers.get('Authorization')return {'user_agent': user_agent,'content_type': content_type,'has_auth': bool(auth),'all_headers': headers}

6.2 自定义头处理(如 API Key)

@app.route('/api/data')
def api_data():api_key = request.headers.get('X-API-Key')if not api_key or api_key != 'your-secret-key-123':return {'error': '未授权'}, 401return {'data': '敏感信息'}

七、Cookies 处理

7.1 读取 Cookies

@app.route('/profile')
def profile():username = request.cookies.get('username')theme = request.cookies.get('theme', 'light')  # 默认值if not username:return '请先登录', 302, {'Location': '/login'}return f'欢迎,{username}!当前主题:{theme}'

7.2 设置 Cookies(需结合响应对象)

from flask import make_response@app.route('/set-cookie')
def set_cookie():resp = make_response('Cookie 已设置')resp.set_cookie('username', 'alice', max_age=3600)        # 1小时resp.set_cookie('theme', 'dark', max_age=3600)resp.set_cookie('session_id', 'abc123', httponly=True, secure=True)  # 安全设置return resp

✅ 推荐设置 httponly=True 防 XSS,secure=True(HTTPS 环境)。


八、高级技巧与最佳实践

8.1 请求验证装饰器

from functools import wrapsdef validate_json(*required_fields):def decorator(f):@wraps(f)def decorated(*args, **kwargs):if not request.is_json:return {'error': 'JSON required'}, 400data = request.get_json()if not data:return {'error': 'Invalid JSON'}, 400for field in required_fields:if field not in data:return {'error': f'缺少字段: {field}'}, 400return f(*args, **kwargs)return decoratedreturn decorator@app.route('/api/product', methods=['POST'])
@validate_json('name', 'price')
def create_product():data = request.get_json()return {'message': '商品创建成功', 'product': data}

8.2 请求预处理(@before_request

@app.before_request
def before_request():app.logger.info(f"📥 {request.method} {request.url}")# 维护模式if app.config.get('MAINTENANCE'):if request.endpoint not in ['maintenance', 'health']:return '系统维护中...', 503# API 版本检查if request.path.startswith('/api/'):version = request.headers.get('X-API-Version')if version and version < '2.0':return {'error': 'API 版本已弃用'}, 410

8.3 处理复杂表单结构

@app.route('/complex', methods=['POST'])
def complex_form():user_data = {'name': request.form.get('user.name'),'email': request.form.get('user.email'),'profile': {'age': request.form.get('user.profile.age', type=int),'city': request.form.get('user.profile.city')}}skills = request.form.getlist('skills')  # ['Python', 'Flask']return {'user': user_data,'skills': skills}

九、request 对象属性速查表

属性/方法

说明

示例

request.method

请求方法

'GET', 'POST'

request.args

查询参数(ImmutableMultiDict)

request.args.get('page')

request.form

表单数据

request.form['name']

request.files

上传文件

request.files['avatar']

request.json

JSON 数据(只读)

request.json.get('id')

request.get_json()

获取 JSON(可 force)

data = request.get_json()

request.headers

请求头

request.headers.get('User-Agent')

request.cookies

Cookies

request.cookies.get('session')

request.data

原始字节数据

request.get_data()

request.values

所有输入(args + form)

request.values.get('search')

request.url

完整 URL

https://...?q=test

request.remote_addr

客户端 IP

'192.168.1.1'


十、安全与最佳实践

✅ 推荐做法

  • 使用 get() 而非直接索引(避免 KeyError
  • 对用户输入进行验证与清理
  • 限制文件上传类型和大小
  • 使用 secure_filename() 处理文件名
  • 敏感 Cookie 设置 httponlysecure
  • 使用装饰器统一处理验证逻辑

❌ 避免

# ❌ 不安全:未验证
username = request.form['username']# ❌ 危险:直接拼接文件名
file.save(f"uploads/{request.files['file'].filename}")# ❌ 不推荐:未处理异常
data = request.get_json(force=True)  # 可能抛出 BadRequest

十一、总结

request 对象是 Flask 应用与客户端通信的桥梁。掌握它的各种用法,不仅能提升开发效率,更能增强应用的安全性和健壮性。

🔑 核心要点回顾

  1. request 是上下文局部对象,线程安全。
  2. 支持多种数据格式:query、form、json、files、headers、cookies。
  3. 善用 @before_request 和装饰器进行预处理。
  4. 始终验证输入,防止注入攻击。
  5. 文件上传需严格校验类型和路径。
http://www.lryc.cn/news/626965.html

相关文章:

  • 解决前端项目启动时找不到esm文件的问题
  • STM32F407VGT6从零建立一个标准库工程模板+VSCode或Keil5
  • Spring Boot 定时任务与 xxl-job 灵活切换方案
  • 双分支混合光伏预测模型
  • 第5.7节:awk赋值运算
  • 技术半衰期悖论:AI时代“不可替代领域“的深耕地图
  • AIStarter服务器版深度解析:与桌面版对比,解锁云端AI开发新体
  • 如何代开VSCode的settigns.json文件
  • 【JavaEE】多线程(线程安全问题)
  • Gin传参和接收参数的方式
  • BM25 系列检索算法
  • 自学大语言模型之Transformer的Trainer
  • 工业电脑选得好生产效率节节高稳定可靠之选
  • 0基础安卓逆向原理与实践:第5章:APK结构分析与解包
  • 华为仓颉语言的class(类)初步
  • 比剪映更轻量!SolveigMM 视频无损剪切实战体验
  • 将集合拆分成若干个batch,并将batch存于新的集合
  • ubuntu下安装vivado2015.2时报错解决方法
  • 换根DP(P3478 [POI 2008] STA-StationP3574 [POI 2014] FAR-FarmCraft)
  • Qt 中最经典、最常用的多线程通信场景
  • 通过自动化本地计算磁盘与块存储卷加密保护数据安全
  • 链表-24.两两交换链表中的结点-力扣(LeetCode)
  • ansible playbook 实战案例roles | 实现基于firewalld添加端口
  • SSM从入门到实战:2.1 MyBatis框架概述与环境搭建
  • 【LeetCode 热题 100】279. 完全平方数——(解法三)空间优化
  • innovus auto_fix_short.tcl
  • 代码随想录Day57:图论(寻宝prim算法精讲kruskal算法精讲)
  • 3D检测笔记:相机模型与坐标变换
  • 今日行情明日机会——20250820
  • 算法提升树形数据结构-(线段树)