在 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, request
app = 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):
    # 仍可访问 request
    resp.headers['X-Request-Method'] = request.method
    return 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, proxy2
        return x_forwarded_for.split(',')[0].strip()
    x_real_ip = request.headers.get('X-Real-IP')
    if x_real_ip:
        return x_real_ip
    return 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')           # 返回字符串或 None
    page = 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': '搜索关键词不能为空'}, 400
    page = request.args.get('page', 1, type=int)
    if page < 1:
        page = 1
    limit = 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 missing
        password = request.form.get('password')  # 返回 None if missing
        remember = '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_filename
UPLOAD_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 '没有文件上传', 400
        file = request.files['file']
        if file.filename == '':
            return '未选择文件', 400
        if 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-Type
    if not request.is_json:
        return {'error': 'Content-Type must be application/json'}, 400
    # 获取 JSON 数据
    data = request.get_json()
    if not data:
        return {'error': '无效的 JSON 数据'}, 400
    name = 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
    }), 2015.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': '未授权'}, 401
    return {'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 wraps
def validate_json(*required_fields):
    def decorator(f):
        @wraps(f)
        def decorated(*args, **kwargs):
            if not request.is_json:
                return {'error': 'JSON required'}, 400
            data = request.get_json()
            if not data:
                return {'error': 'Invalid JSON'}, 400
            for field in required_fields:
                if field not in data:
                    return {'error': f'缺少字段: {field}'}, 400
            return f(*args, **kwargs)
        return decorated
    return 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 版本已弃用'}, 4108.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 设置 httponly和secure
- 使用装饰器统一处理验证逻辑
❌ 避免
# ❌ 不安全:未验证
username = request.form['username']
# ❌ 危险:直接拼接文件名
file.save(f"uploads/{request.files['file'].filename}")
# ❌ 不推荐:未处理异常
data = request.get_json(force=True)  # 可能抛出 BadRequest十一、总结
request 对象是 Flask 应用与客户端通信的桥梁。掌握它的各种用法,不仅能提升开发效率,更能增强应用的安全性和健壮性。
🔑 核心要点回顾:
- request是上下文局部对象,线程安全。
- 支持多种数据格式:query、form、json、files、headers、cookies。
- 善用 @before_request和装饰器进行预处理。
- 始终验证输入,防止注入攻击。
- 文件上传需严格校验类型和路径。