请求与响应

request 对象封装了当前 HTTP 请求的全部信息,视图函数的返回值则被 Flask 转换为响应对象。理解这两端是编写 Web 应用的核心。

请求对象

flask.request 是一个线程/上下文安全的代理,在视图中直接导入使用:

from flask import request

@app.get("/query")
def query():
    q = request.args.get("q", "")                    # 查询参数 ?q=...
    page = request.args.get("page", 1, type=int)     # type= 自动转换,失败用默认值
    tags = request.args.getlist("tag")               # ?tag=a&tag=b → ["a", "b"]
    return {"q": q, "page": page, "tags": tags}

常用属性:

属性内容
request.argsURL 查询参数(MultiDict)
request.form表单数据(POST,application/x-www-form-urlencoded / multipart
request.get_json()JSON 请求体
request.files上传的文件
request.headers请求头
request.cookiesCookie
request.method / request.path / request.url方法与路径
request.remote_addr客户端 IP(代理后需配合 ProxyFix)

表单与 JSON

@app.post("/submit")
def submit():
    name = request.form.get("name")                 # 表单字段
    data = request.get_json(silent=True) or {}      # silent=True:非 JSON 时返回 None 而非报错
    return {"name": name, "data": data}

request.get_json() 默认要求 Content-Type: application/json,否则抛 415。

文件上传

import os
from werkzeug.utils import secure_filename

@app.post("/upload")
def upload():
    f = request.files.get("file")
    if f is None or f.filename == "":
        return {"error": "no file"}, 400
    filename = secure_filename(f.filename)          # 清洗文件名,防目录穿越
    f.save(os.path.join(app.config["UPLOAD_FOLDER"], filename))
    return {"saved": filename}, 201

记得限制大小:app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024(超出自动返回 413)。

响应的多种返回形式

视图返回值会被 Flask 自动包装:

@app.get("/examples")
def examples():
    return "纯文本"                          # 200,text/html
    return {"ok": True}                      # dict → JSON
    return [1, 2, 3]                         # list → JSON(Flask 2.2+)
    return "Created", 201                    # (body, status)
    return {"ok": True}, 200, {"X-Foo": "1"} # (body, status, headers)
    return render_template("page.html")      # 模板渲染结果

精细控制:make_response

需要设置头、Cookie 等时显式构造响应对象:

from flask import make_response

@app.get("/resp")
def resp():
    resp = make_response(render_template("page.html"), 200)
    resp.headers["Cache-Control"] = "no-store"
    resp.set_cookie("sid", "abc", httponly=True, samesite="Lax", max_age=3600)
    return resp

重定向与文件下载

from flask import redirect, url_for, send_file

@app.post("/save")
def save():
    ...
    return redirect(url_for("index"))        # 处理完 POST 后重定向(PRG 模式)

@app.get("/report")
def report():
    return send_file("reports/latest.pdf", as_attachment=True)

请求钩子

在请求生命周期中插入逻辑:

@app.before_request
def load_user():
    g.user = lookup_user(request.cookies.get("sid"))

@app.after_request
def add_security_headers(resp):
    resp.headers["X-Content-Type-Options"] = "nosniff"
    return resp                              # after_request 必须返回响应对象