1.3请求与响应(RequestandResponse)


1.3 请求与响应(Request and Response)

本节摘要:视图函数的两端是请求与响应——request 对象读取客户端发来的数据(参数、表单、JSON、文件),response 对象控制返回内容(字符串、模板、JSON、重定向、状态码)。本节把"数据怎么进、怎么出"讲透。

你能学到什么

阅读完本节,你应当能够:

  1. 用 request 获取查询参数、表单数据、JSON、请求头
  2. 用多种方式构造响应(字符串、JSON、重定向、模板)
  3. 控制响应状态码与响应头
  4. 处理文件上传
  5. 理解请求上下文与线程安全---

问题与直觉:视图函数的两头

视图函数像一个"处理站":左边是进来的请求(request),右边是出去的响应(response)。客户端可能通过 URL 参数、表单、JSON 体、请求头送来数据;你要把这些读出来处理,再把结果以适当形式返回。

Flask 把这两头都封装成全局对象:request(当前请求)与 response(可构造的响应)。它们"看似全局,实则线程安全"——每个请求都有自己的一份。

💡 关键直觉:request 不是"你的请求",是"当前线程的请求"。Flask 用请求上下文(见 2.5)保证并发下每个请求拿到自己的数据,这也是"上下文"概念首次登场。

核心原理:request 对象

读取客户端数据

from flask import Flask, request app = Flask(__name__) @app.route('/search') def search(): # 1. 查询参数:/search?q=python&page=2 q = request.args.get('q', '默认值') page = request.args.get('page', 1, type=int) # 2. 表单数据(POST):request.form # username = request.form.get('username') # 3. JSON 数据(POST):request.get_json() # data = request.get_json() # 4. 请求头 ua = request.headers.get('User-Agent') # 5. 请求方法 method = request.method return f"q={q}, page={page}, UA={ua[:30]}, method={method}"

request 常用属性

属性 用途
request.args 查询参数(URL 中 ? 后)
request.form 表单数据(POST 表单)
request.json / get_json() JSON 请求体
request.files 上传的文件
request.headers 请求头
request.method HTTP 方法
request.path 请求路径(不含查询串)
request.url 完整 URL

工程实践要点:response 的多种返回

返回字符串与状态码

@app.route('/plain') def plain(): return "纯文本", 200 # (内容, 状态码) @app.route('/created') def created(): return "创建成功", 201 @app.route('/error') def error(): return "页面不存在", 404

返回 JSON(API 常用)

from flask import jsonify @app.route('/api/data') def api_data(): data = {"name": "Flask", "version": "3.x", "features": ["路由", "模板"]} return jsonify(data)

jsonify 自动设置 Content-Type 为 application/json 并序列化。

重定向

from flask import redirect, url_for @app.route('/old-page') def old_page(): return redirect(url_for('index')) @app.route('/') def index(): return "首页"

自定义响应对象

from flask import make_response @app.route('/custom') def custom(): resp = make_response("自定义响应") resp.status_code = 202 resp.headers['X-Custom-Header'] = 'hello' return resp

make_response 让你完全控制状态码与响应头。

⚠️ 常见坑:dict 不能直接 returnreturn {"a": 1} 在旧版 Flask 会报错;Flask 3.x 虽支持,但明确返回 JSON 用 jsonify 更安全清晰。

动手实验:请求回显

from flask import Flask, request, jsonify app = Flask(__name__) @app.route('/echo', methods=['GET', 'POST']) def echo(): result = { "method": request.method, "path": request.path, "args": dict(request.args), "json": request.get_json() if request.is_json else None, "user_agent": request.headers.get('User-Agent'), } return jsonify(result) if __name__ == '__main__': app.run(debug=True)

访问 /echo?name=flask 或 POST JSON,观察返回的请求信息——这个"回显"工具是调试 API 的利器

进阶:文件上传

import os from flask import request from werkzeug.utils import secure_filename @app.route('/upload', methods=['POST']) def upload(): file = request.files.get('file') if not file: return "没有文件", 400 # secure_filename 清理文件名(防路径穿越) filename = secure_filename(file.filename) file.save(os.path.join('uploads', filename)) return f"已保存: {filename}", 201

文件上传要点request.files 取文件、secure_filename 清理文件名(防 ../../etc/passwd 类攻击)、file.save 保存到指定目录。

FAQ:请求响应高频问题

问:request.args 和 request.form 有什么区别?
args 是 URL 查询参数(?name=xx),form 是 POST 表单体。GET 表单数据在 args,POST 表单数据在 form。

问:JSON 请求体怎么读?
request.get_json()——要求请求头 Content-Type 为 application/json,否则返回 None。

问:为什么能直接 return 字符串?
Flask 自动把字符串包装成 Response(默认状态码 200,Content-Type text/html)。想精细控制就用 make_response。

问:并发下 request 会混乱吗?
不会。Flask 用请求上下文(LocalProxy)保证每个线程/协程拿到自己的 request——这正是 2.5 上下文章节的核心。

深入理解:请求对象属性速查

request 对象承载了客户端发来的全部信息,常用属性如下:

属性 内容 示例
request.method HTTP 方法 'GET' / 'POST'
request.path 路径(不含查询串) '/users'
request.full_path 路径+查询串 '/users?page=2'
request.args URL 查询参数(不可变字典) request.args.get('page')
request.form 表单数据(POST) request.form.get('name')
request.files 上传的文件 request.files.get('avatar')
request.json JSON 请求体(已解析为字典) request.json['name']
request.headers 请求头 request.headers.get('User-Agent')
request.cookies Cookie 字典 request.cookies.get('session')
request.remote_addr 客户端 IP '127.0.0.1'
request.url 完整 URL '「相关地址请参见官方文档」

args 与 form 的区分request.args 取的是 URL 里的参数(?page=2),request.form 取的是 POST 表单体——两者不是一回事。新手最常见错误是把 POST 提交的数据用 args 取,结果永远拿到 None。

# 正确区分 @app.route('/search') def search(): keyword = request.args.get('q') # URL 参数:/search?q=python @app.route('/login', methods=['POST']) def login(): username = request.form.get('username') # 表单体

同时兼容多种请求体

实际项目中,同一个接口可能同时收到表单、JSON、查询参数——可以用统一封装:

from flask import request def get_param(name, default=None): # 依次从 JSON、表单、查询参数中取值 if request.is_json and name in request.json: return request.json[name] if name in request.form: return request.form[name] return request.args.get(name, default)

响应对象的三种构建方式对比

方式 写法 适用场景
直接返回字符串 return 'hello' 简单文本/小页面
返回元组 return 'ok', 201, {'X-Custom': '1'} 需要状态码/响应头
构造 Response resp = make_response(...) 需要修改响应头/Cookie 等
from flask import make_response @app.route('/download') def download(): resp = make_response('文件内容') resp.headers['Content-Disposition'] = 'attachment; filename=report.txt' resp.set_cookie('downloaded', 'yes', max_age=3600) return resp

选择原则:简单场景用直接返回(省事);需要精细控制(下载、Cookie、缓存头)用 make_response。

常见请求响应问题排查

现象 原因 解法
取 POST 数据总是 None 用了 args 而非 form/json 确认数据在 body 还是 URL
request.json 为 None 请求头没有 Content-Type: application/json 前端加请求头,或改用 form
返回中文乱码 响应编码不对 Flask 默认 utf-8,检查前端 charset
想要 JSON 却返回 HTML 视图返回了字符串 返回 dict 或 jsonify
改响应头不生效 直接 return 字符串 用 make_response

核心回顾

  • request.args:URL 查询参数;request.form:POST 表单体;request.json:JSON 请求体。
  • 取参统一封装:用 get_param 依次从 JSON、表单、查询参数取值。
  • 响应三种方式:直接返回字符串、返回元组(值+状态码+头)、make_response 精细控制。
  • jsonify:把字典转成 JSON 响应,自动设置 Content-Type。
  • Cookie 设置:make_response + set_cookie,可设过期时间与路径。
  • 排查口诀:取不到值先确认"数据在 body 还是 URL"。

请求调试三板斧

开发 Web 应用,调试请求是日常工作。掌握这三个工具,调试效率翻倍:

第一板斧:浏览器的开发者工具(F12)。 打开 Network 面板,刷新页面,能看到每个请求的方法、URL、状态码、耗时、请求头与响应体。排查"页面为什么 404/500/空白"时,先看 Network 里的状态码——90% 的问题一眼定位。Console 面板看 JS 错误,Elements 面板看最终渲染的 HTML。

第二板斧:curl 命令行。 快速验证接口行为,不依赖浏览器:

# GET 请求,带查询参数 curl "http://127.0.0.1:5000/search?q=flask" # POST 表单 curl -X POST http://127.0.0.1:5000/login -d "username=alice&password=123" # POST JSON curl -X POST http://127.0.0.1:5000/api/users -H "Content-Type: application/json" -d '{"name": "alice"}' # 显示响应头 curl -i http://127.0.0.1:5000/

第三板斧:Postman / 可视化 API 工具。 图形化构造请求、保存请求集、写自动化测试。团队联调时,Postman 的请求集合可以共享,是新同事上手项目的加速器。

一个调试实战场景:前端说"接口报错了"。你用 curl 复现:curl -X POST 「相关地址请参见官方文档」 -d '{"name":"x"}'——如果 curl 也报错,说明是后端问题;如果 curl 正常但前端报错,说明是前端请求格式问题(比如忘了 Content-Type)。用 curl 复现,是"前后端谁的问题"最快的判断法

关于 request 数据类型的坑request.form 是 ImmutableMultiDict,request.args 也是——它们支持 getgetlist(取同名多个值)、to_dict。当表单有多个同名 checkbox 时,用 request.form.getlist('tags') 才能取全。

响应调试:改完响应头不生效时,检查是否用了 make_response;中文乱码时检查 Content-Type 是否带 charset=utf-8(Flask 的 jsonify 和 render_template 默认都带)。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U