当前位置: 首页 > 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.dtcms.com/a/340834.html

相关文章:

  • 【NFTurbo】基于Redisson滑动窗口实现验证码发送限流
  • 如何在高并发下,保证共享数据的一致性
  • RabbitMQ的架构设计是什么样的
  • Unity 之如何使用Pico4u锚点功能实现一个世界锁GameRoot
  • 第二十七天:游戏组队问题
  • 【GPT入门】第49课 LlamaFacotory 训练千问
  • Mac电脑 Pixelmator Pro 专业图像处理【媲美PS】
  • UE5 InVideo插件打包报错
  • Linux 下实现“连 root 都无法查看和删除”的加密文件夹(附一键挂载 + 自动超时退出)
  • 【P7071 [CSP-J2020] 优秀的拆分 - 洛谷 https://www.luogu.com.cn/problem/P7071】
  • 织梦素材站网站源码 资源付费下载交易平台源码
  • 棒子出品,无须破解!
  • PyTorch API 6
  • 深度学习实战116-基于Qwen大模型与层次化对齐评分模型(HASM)的中学数学主观题自动批改系统
  • 常见开源协议详解:哪些行为被允许?哪些被限制?
  • AV1视频编码器2024-2025技术进展与行业应用分析
  • 本地部署的终极多面手:Qwen2.5-Omni-3B,视频剪、音频混、图像生、文本写全搞定
  • 第四章:大模型(LLM)】07.Prompt工程-(5)self-consistency prompt
  • PyTorch 深度学习常用函数总结
  • 使用 SSH 方式克隆 GitHub 仓库没有权限解决办法
  • [递归回溯]679. 24 点游戏
  • LINUX 820 shell:shift,expect
  • 第5.8节:awk自增自减运算
  • linux的内核符号表
  • 服装外贸系统软件怎么用才高效防风险?
  • 曲面的交线的切向量计算及其在坐标平面投影的几何分析
  • 有向图(Directed Graph)和有向无环图(Directed Acyclic Graph,DAG)代码实践
  • 反向Shell(Reverse Shell)
  • Meta 再次重组人工智能部门
  • Visual Studio 2010 简体中文旗舰版 安装全过程详解(附安装包下载)