处理http的请求与响应
一、flask的生命周期
web 服务器: app.run() / nginx / uwsgi wsgi: app=Flask() / django-application 全局钩子(权限验证、访问日志等): @app.before_request / django-中间键 路由: @app.route() 视图:默认函数视图+类视图, 最终转换为一个request,这里可以处理数据,操作数据库等
二、请求
1.request的常用属性
文档: https://flask.palletsprojects.com/en/2.0.x/api/#flask.Request
-
request:flask中代表当前请求的
request 对象
-
作用:在视图函数中取出本次客户端的请求数据
-
导入:
from flask import request
-
源码位置:
-
代理类 from flask import request --来源-> from flask.globals import request
-
源码类:from flask.wrappers import Request
-
基类:from werkzeug.wrappers import Request as RequestBase
request,常用的属性如下:
属性 | 说明 | 类型 |
---|---|---|
data | 记录请求体的数据,并转换为字符串 只要是通过其他属性无法识别转换的请求体数据 最终都是保留到data属性中 例如:有些公司开发微信小程序,原生IOS或者安卓,这一类客户端有时候发送过来的数据就不一定是普通的form表单或查询字符串或json | bytes类型 |
form | 记录请求中的html表单数据 | ImmutableMultiDict |
args | 记录请求中的查询字符串,也可以是query_string | ImmutableMultiDict |
cookies | 记录请求中的cookie信息 | Dict |
headers | 记录请求中的请求头 | ImmutableMultiDict |
method | 记录请求使用的HTTP方法 | GET/POST |
url | 记录请求的URL地址 | string |
files | 记录请求上传的文件列表 | ImmutableMultiDict |
json | 记录ajax请求的json数据 | Dict |
2.获取请求中各项数据
1)获取查询字符串,代码:
from flask import Flask, request from urllib.parse import parse_qs app = Flask(__name__) @app.route("/qs") def qs(): """ 获取客户端请求的查询字符串参数 :return: """ """ 请求url:http://127.0.0.1:5000/qs?user=xiaoming&age=16 """ # 获取原始的查询字符串参数,格式:bytes # print(request.query_string) # b'user=xiaoming&age=16' # # 针对原始的查询字符串参数,转换成字典格式 # query_string = parse_qs(request.query_string.decode()) # print(query_string) # {'user': ['xiaoming'], 'age': ['16']} # # 获取参数值 # print(query_string["user"][0]) # # 获取查询字符串参数,格式:ImmutableMultiDict # print(request.args) # # ImmutableMultiDict([('user', 'xiaoming'), ('age', '16')]) # # 获取单个参数值 # print(request.args["user"]) # print(request.args["age"]) # print(request.args.get("age")) """ 请求url:http://127.0.0.1:5000/qs?user=xiaoming&fav=shopping&fav=coding&fav=rap """ # print(request.args["user"]) # 'xiaoming' # print(request.args["fav"]) # 'shopping' # print(request.args.get("user")) # 'xiaoming' print(request.args.getlist("fav")) # ['shopping', 'coding', 'rap'] return "hello, flask" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
2) 获取请求体,代码:
import json from flask import Flask, request app = Flask(__name__) @app.route("/form1", methods=["post"]) def form1(): """ 获取客户端请求的请求体[表单] :return: """ """ 获取表单数据 请求url: """ """获取表单数据[不包含上传文件]""" # print(request.form) # # ImmutableMultiDict([('username', 'root'), ('password', '123456'), ('fav', 'swimming'), ('fav', 'watch TV')]) # # 获取表单项数据[单个值] # print(request.form.get("username")) # root # # 获取表单项数据[多个值] # print(request.form.getlist("fav")) # ['swimming', 'watch TV'] """获取表单数据的上传文件""" # print(request.form.get("username")) # # 获取所有上传文件 # print(request.files) # ImmutableMultiDict([('avatar', <FileStorage: 's.png' ('image/png')>)]) # # 根据name值获取单个上传文件 # print(request.files.get("avatar")) # <FileStorage: 's.png' ('image/png')> # # 根据name值获取多个上传文件 # print(request.files.getlist("avatar")) # [<FileStorage: 'a.png' ('image/png')>, <FileStorage: 's.png' ('image/png')>] return "hello, flask" @app.route("/data", methods=["post"]) def data(): """ 获取客户端请求的请求体[ajax] :return: """ """判断本次客户端是否是ajax请求获取本次客户端提交的数据格式是否是json""" # print(request.is_json) """获取客户端请求体中的json数据""" # print(request.json) # {'username': 'root', 'password': '123456'} """获取客户端请求体的原始数据""" # print(request.data) # b'{\n "username": "root",\n "password": "123456"\n}' # 原始数据转json格式 # print(json.loads(request.data)) # {'username': 'root', 'password': '123456'} """接收其他格式类型的数据""" # print(request.data) return "hello, flask" @app.route("/file", methods=["post", "put", "patch"]) def file(): """ 接收上传文件并保存文件 :return: """ avatar = request.files.get("avatar") print(avatar) # 调用FileStorage提供的save方法就可以保存文件了 avatar.save("./avatar.png") return "hello, flask" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
3)获取请求头等相关数据,代码:
import json from flask import Flask, request app = Flask(__name__) @app.route("/header", methods=["get", "post", "put", "patch","delete"]) def header(): """ 获取请求头等其他请求信息 :return: """ # # 获取请求头所有信息 # print(request.headers, type(request.headers)) # # """ # 获取单个请求头信息 # """ # # 基于get使用请求头原始属性名获取, User-Agent 客户端的网络代理工具名称 # print(request.headers.get("User-Agent")) # PostmanRuntime/7.26.10 # # 把原始属性名转换成小写下划线格式来获取 # print(request.user_agent) # PostmanRuntime/7.26.10 # # # 获取本次客户端请求的服务端地址 # print(request.host) # 127.0.0.1:5000 # # # 获取本次客户端请求提交的数据格式 # print(request.content_type) # multipart/form-data; # # # 获取本次客户端请求的uri路径 # print(request.path) # /header # # 获取本次客户端请求完整url地址 # print(request.url) # http://127.0.0.1:5000/header # # 获取本次客户端请求的服务端域名 # print(request.root_url) # http://127.0.0.1:5000/ # # # 获取本次客户端的Http请求方法或请求动作 # print(request.method) # POST # # # 获取本次客户端的IP地址 # print(request.remote_addr) # 127.0.0.1 # # # 获取本次客户端获取到的服务端信息 # print(request.server) # ('0.0.0.0', 5000) # 获取本次客户端请求时,服务端的系统系统环境变量信息 # print(request.environ) """ 获取自定义请求头 """ print(request.headers.get("company")) # flask.edu return "hello, flask" if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
二、响应
flask默认支持2种响应方式:
- 数据响应: 默认响应html文本,也可以返回 JSON格式,或其他媒体类型的文件
- 页面响应: 重定向,url_for 视图之间的跳转
响应的时候,flask也支持自定义http响应状态码
1.响应html文本
from flask import Flask, make_response, Response app = Flask(__name__) @app.route("/") def index(): """响应HTML文本,并设置响应状态码""" # return "<h1>hello, flask</h1>", 400 """通过make_response返回Response对象""" # response = make_response("<h1>hello, flask</h1>", 201) # print(response) # return response """通过Response返回Response对象""" response = Response("<h1>hello, flask</h1>", 201) return response if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
2.返回JSON数据
在 Flask 中可以直接使用 jsonify 生成一个 JSON 的响应
flask中返回json 数据,都是flask的jsonify方法返回就可以了,直接return只能返回字典格式的json数据。
import json from flask import Flask, make_response, Response, jsonify app = Flask(__name__) @app.route("/jsonapi") def jsonapi(): """响应json数据[原生写法]""" data = {"name": "xiaoming", "age": 16} # return json.dumps(data), 200, {"Content-Type": "application/json"} # return Response(json.dumps(data), 200, {"Content-Type": "application/json"}) """响应json数据[jsonify]""" data = {"name": "xiaoming", "age": 16} response = jsonify(data) print(response) return response if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
3.响应指定媒体类型的文件
import json from flask import Flask, make_response, Response, jsonify app = Flask(__name__) @app.route("/img") def img(): """响应图片格式给客户端""" with open("avatar.png", "rb") as f: data = f.read() return data, 200, {"Content-Type": "image/png"} # MIME类型 if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)
4.自定义状态码和响应头
在 Flask 中,可以很方便的返回自定义状态码,以实现不符合 http 协议的状态码,例如:status code: 666
from flask import Flask, request, redirect, url_for, Response app = Flask(__name__) @app.route("/") def index(): """自定义响应头""" return "hello, flask", 201, {"Company": "flask.edu"} if __name__ == '__main__': app.run(host="0.0.0.0", port=5000, debug=True)