Flask入门教程(七):请求与响应——Web应用的核心数据流

1. 请求对象------request

Flask通过全局代理对象request提供所有请求信息。虽然它是"全局"对象,但Flask内部通过线程隔离机制确保每个请求获取的是自己的数据,不会互相干扰。

复制代码
from flask import Flask, request

app = Flask(__name__)

@app.route("/debug")
def debug():
    return f"""
    <h1>请求调试信息</h1>
    <ul>
        <li>方法:{request.method}</li>
        <li>路径:{request.path}</li>
        <li>完整 URL:{request.url}</li>
        <li>主机:{request.host}</li>
        <li>客户端 IP:{request.remote_addr}</li>
        <li>User-Agent:{request.headers.get('User-Agent')}</li>
    </ul>
    """

访问 http://127.0.0.1:5000/debug?foo=bar 即可看到请求的详细信息。

2. 获取查询参数------request.args

URL中?后面的参数称为查询参数(Query String) ,使用request.args读取,它类似于一个字典。

复制代码
@app.route("/search")
def search():
    keyword = request.args.get("keyword", "")
    page = request.args.get("page", "1")
    return f"""
    <h1>搜索结果</h1>
    <p>关键词:{keyword}</p>
    <p>页码:{page}</p>
    """
测试URL 结果
/search?keyword=flask&page=2 关键词:flask,页码:2
/search?keyword=RUNOOB 关键词:RUNOOB,页码:1(默认值)

💡 推荐使用.get()方法request.args.get("key")在key不存在时返回None(或指定的默认值),而直接使用request.args["key"]在key不存在时会抛出KeyError,导致返回400错误页面。

3. 获取表单数据------request.form

处理POST请求提交的表单数据,使用request.form

复制代码
@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        username = request.form.get("username", "")
        password = request.form.get("password", "")

        if not username or not password:
            return "<h1>错误</h1><p>用户名和密码不能为空</p>", 400

        return f"<h1>注册成功</h1><p>欢迎 {username} 加入 RUNOOB!</p>"

    # GET请求时显示注册表单
    return """
    <h1>注册</h1>
    <form method="post">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="password" name="password"></p>
        <p><input type="submit" value="注册"></p>
    </form>
    """

⚠️ 注意 :表单必须设置method="post",否则数据会通过URL查询字符串发送(GET方式),敏感信息会暴露在URL中。

4. 获取JSON数据------request.json

现代Web开发中,JSON是最常见的数据格式。当客户端发送Content-Type: application/json的请求时,使用request.json获取解析后的数据:

复制代码
@app.post("/api/user")
def create_user():
    data = request.json
    name = data.get("name", "未知")
    email = data.get("email", "未提供")
    return {
        "message": "用户创建成功",
        "name": name,
        "email": email
    }

curl测试:

复制代码
$ curl -X POST http://127.0.0.1:5000/api/user \
  -H "Content-Type: application/json" \
  -d '{"name": "runoob", "email": "test@runoob.com"}'
复制代码
{
  "message": "用户创建成功",
  "name": "runoob",
  "email": "test@runoob.com"
}

5. 文件上传------request.files

处理上传的文件使用request.files,配合Werkzeug提供的secure_filename()确保文件名安全:

复制代码
import os
from werkzeug.utils import secure_filename

UPLOAD_DIR = "uploads"

@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

        filename = secure_filename(file.filename)
        os.makedirs(UPLOAD_DIR, exist_ok=True)
        file.save(os.path.join(UPLOAD_DIR, filename))
        return f"文件 {filename} 上传成功"

    return """
    <h1>上传文件</h1>
    <form method="post" enctype="multipart/form-data">
        <p><input type="file" name="file"></p>
        <p><input type="submit" value="上传"></p>
    </form>
    """
关键点 说明
secure_filename() 过滤路径遍历等危险字符,如../../etc/passwd会被处理为etc_passwd
enctype="multipart/form-data" 表单包含文件上传时必须设置此属性
os.makedirs(..., exist_ok=True) 确保上传目录存在,exist_ok=True防止目录已存在时报错

6. 响应类型完全指南

视图函数可以返回多种类型的数据,Flask会自动将它们转换为合适的HTTP响应。

返回字符串

返回的字符串作为HTML响应体,状态码默认200,Content-Typetext/html

复制代码
@app.route("/hello")
def hello():
    return "<h1>Hello, World!</h1>"

返回字典或列表(JSON)

自动调用jsonify()转换为JSON响应,Content-Typeapplication/json

复制代码
@app.get("/api/posts")
def get_posts():
    return {
        "status": "ok",
        "data": [
            {"id": 1, "title": "Flask 入门教程"},
            {"id": 2, "title": "RESTful API 设计"},
        ]
    }

@app.get("/api/tags")
def get_tags():
    return ["Python", "Flask", "Web 开发"]

返回元组------控制状态码和响应头

元组有三种组合形式:

复制代码
# 形式1:(body, status_code)
@app.get("/not-found")
def not_found():
    return "<h1>页面不存在</h1>", 404

# 形式2:(body, headers_dict)
@app.get("/custom-header")
def custom_header():
    return "OK", {"X-Custom-Header": "runoob"}

# 形式3:(body, status_code, headers_dict)
@app.post("/api/login")
def api_login():
    return {"token": "abc123"}, 201, {"X-RateLimit": "100"}

重定向------redirect()

使用redirect()函数将用户引导到另一个URL:

复制代码
from flask import redirect, url_for

@app.route("/")
def index():
    return redirect(url_for("login"))

@app.route("/old-page")
def old_page():
    # 永久迁移使用301状态码
    return redirect(url_for("new_page"), code=301)

@app.route("/new-page")
def new_page():
    return "<h1>这是新页面</h1>"
状态码 含义 适用场景
302(默认) Found 临时重定向
303 See Other 表单提交后重定向(PRG模式)
301 Moved Permanently 永久迁移

终止请求------abort()

使用abort()立即终止当前请求并返回HTTP错误:

复制代码
from flask import abort

@app.route("/post/<int:post_id>")
def view_post(post_id):
    if post_id < 1 or post_id > 100:
        abort(404)
    return f"<h1>文章 #{post_id}</h1>"

@app.route("/admin")
def admin():
    abort(403, description="你没有权限访问此页面")

make_response------手动控制响应

当需要手动设置Cookie或自定义响应头时,使用make_response()

复制代码
from flask import make_response

@app.route("/set-cookie")
def set_cookie():
    resp = make_response("<h1>Cookie已设置</h1>")
    resp.set_cookie("theme", "dark", max_age=60*60*24)  # 有效期24小时
    resp.headers["X-Powered-By"] = "RUNOOB-Flask"
    return resp

7. request常用属性速查表

属性 类型 说明 示例值
request.method str HTTP请求方法 "GET", "POST"
request.path str URL路径(不含域名) "/search"
request.url str 完整URL "http://127.0.0.1:5000/search?q=flask"
request.args MultiDict URL查询参数 ?keyword=flask&page=1
request.form MultiDict POST表单数据 username=admin
request.json dictNone JSON请求体(已解析) {"name": "runoob"}
request.files FileMultiDict 上传的文件 request.files["avatar"]
request.headers Headers 请求头 request.headers.get("User-Agent")
request.cookies dict 客户端发来的Cookie request.cookies.get("theme")
request.remote_addr str 客户端IP地址 "127.0.0.1"

8. 响应类型速查表

返回类型 示例 自动转换结果
str return "<h1>Hello</h1>" HTML响应,200 OK
dict return {"key": "value"} JSON响应,200 OK
list return ["a", "b"] JSON响应,200 OK
tuple return "body", 404 自定义状态码
tuple return "body", {"X-Header": "v"} 自定义响应头
tuple return "body", 404, {"X-Header": "v"} 自定义状态码+响应头
Response return make_response("body") 完全控制的响应对象
redirect() return redirect("/login") 302重定向
abort() abort(404) 错误响应

小结

本章全面讲解了Flask的请求与响应机制。请求方面,通过request.args读取URL查询参数,request.form读取POST表单数据,request.json解析JSON请求体,request.files处理文件上传,配合secure_filename()确保安全。响应方面,视图函数可返回字符串(HTML)、字典/列表(JSON)、元组(自定义状态码/响应头),还可以通过redirect()实现重定向、abort()终止请求返回错误、make_response()精细控制响应对象。这些知识构成了Flask Web应用数据流转的核心。

相关推荐
爱勇宝17 分钟前
从前端到全栈,我最后学会的是:先做产品
前端·后端
console.log('npc')20 分钟前
Grill-Me 技能使用教程
前端·大模型·产品·skill·需求
web行路人24 分钟前
AI 全栈学习之旅 - Week4:容器化部署与生产环境实战
python·学习
春涧草茶30 分钟前
慢就是快 - 10-2函数 特殊字面量 返回值
python
真空回流焊炉33 分钟前
数字功率芯片真空共晶设备实操教程与要点解析
前端·人工智能
慢云智慧空间37 分钟前
空间智能与计算机视觉的本质差异:不止于识别,更是空间决策能力
人工智能·python·计算机视觉
mayaairi40 分钟前
JS DOM属性操作完全指南:内容、样式与自定义属性
开发语言·前端·javascript
avi91111 小时前
Threejs新版本后glb导出提示.x问题GLTFExporter,替代3dmax
开发语言·前端·javascript·threejs·glb·gltfexporter
典典分享指南1 小时前
Windows 自动化踩坑实录
python·intellij-idea·pyqt·emacs·visual studio