请求与响应
请求对象
请求对象是全局的,需要导入,这个全局的request,那个视图函数中,就是当次的request对象,不会错乱
| 属性或方法 | 说明 |
|---|---|
| request.method | 提交的方法(GET,POST) |
| request.args | get请求提及的数据 |
| request.form | post请求提交的数据 |
| request.values | post和get提交的数据总和 |
| request.cookies | 客户端所带的cookie |
| request.headers | 请求头里的所有信息(字典) |
| request.path | 不带域名,请求路径 |
| request.full_path | 不带域名,带参数的请求路径 |
| request.script_root | 返回脚本根目录 |
| request.url | 返回请求中的网页地址 |
| request.base_url | 返回请求相对地址 |
| request.url_root | 返回请求网页根目录 |
| request.host_url | 127.0.0.1:5000 |
| request.host | 返回host信息 |
| request.files | 文件上传必备 |
| request.data | 返回请求的数据 |
案例演示
def index():
# 请求对象,是全局的,需要导入,这个全局的request,在哪个视图函数中,就是当次的request对象,不会乱
# request.method 提交的方法
print(request.method)
# request.args get请求提及的数据
print(request.args)
print(request.args.get('name'))
# request.form post请求提交的数据
print(request.form)
# request.values post和get提交的数据总和
print(request.values)
# request.cookies 客户端所带的cookie
print(request.cookies)
# request.headers 请求头
print(request.headers)
print('------')
# request.path 不带域名,请求路径
print(request.path)
# request.full_path 不带域名,带参数的请求路径
print(request.full_path)
# request.script_root
print('服务端:', request.script_root)
# request.url 带域名带参数的请求路径
print(request.url)
# request.base_url 带域名请求路径
print(request.base_url)
# request.url_root 域名
print(request.url_root)
# request.host_url 域名
print(request.host_url)
# request.host 127.0.0.1:500
print(request.host)
# request.files
print(request.files)
# obj = request.files['files']
# obj.save('./xx.jpg')
print(request.data) # django的body
return 'hello'
响应对象
四件套
-
render_template() 模板返回
-
redirect() 重定向
-
jsonify() json格式
-
'' 字符串
from flask import Flask
app = Flask(__name__)
@app.route('/',methods=['GET','POST'])
def index():
# 1.写入响应头-->没有响应对象,先做出一个响应对象
# from .wrappers import Response
res='helloe'
res=make_response(res)
# 往Response的对象中,放入响应头
res.headers['name']='lqz'
# 3 写入cookie
# res.set_cookie('xxx','xxx')
res.delete_cookie('xx') # 删除cookie
return res
"""
set_cookie参数
key, 键
value=’’, 值
max_age=None, 超时时间 cookie需要延续的时间(以秒为单位)如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止
expires=None, 超时时间(IE requires expires, so set it if hasn’t been already.)
path=’/‘, Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问,浏览器只会把cookie回传给带有该路径的页面,这样可以避免将cookie传给站点中的其他的应用。
domain=None, Cookie生效的域名 你可用这个参数来构造一个跨站cookie。如, domain=”.example.com”所构造的cookie对下面这些站点都是可读的:www.example.com 、 www2.example.com 和an.other.sub.domain.example.com 。如果该参数设置为 None ,cookie只能由设置它的站点读取
secure=False, 浏览器将通过HTTPS来回传cookie
httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)
"""
前后端分离和混合
# 前后端混合,cookie 是后端写入的
res.set_cookie('xx','xx') 混合都是这么写的,这样写了,浏览就会把cookie保存到cookie中
本质是后端把cookie放到响应头中,浏览器读到响应头中有cookie,把cookie写入到浏览器中
# 前后端分离后
直接把客户端要存到cookie中的数据,放到响应体中
前端(浏览器,app,小程序),自己取出来,放到相应的位置
浏览器使用js自己写入到cookie
app 自己使用代码写入到某个位置
session的使用和原理
session的使用
from flask import Flask,session # 导入全局的session
# 放值 视图函数中
@app.route('/')
def home():
session['name']='lqz'
return 'ok'
# 取值 视图函数中
@app.route('/')
def home():
session['name']
return 'ok'
源码分析
# django 的这一套,都在 from django.contrib.sessions.middleware import SessionMiddleware
# flask 在flask源码中
-请求来了,会执行 app()
# 整个flask,从请求进来,到请求走的整个流程
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
try:
try:
ctx.push() # 它的源码
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except:
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
ctx.pop(error)
# ctx.push 的 373行左右
if self.session is None:
session_interface = self.app.session_interface
self.session = session_interface.open_session(self.app, self.request)
if self.session is None:
self.session = session_interface.make_null_session(self.app)
# app.session_interface 就是Flask对象中有个session_interface对象
SecureCookieSessionInterface()
open_session:请求来了,从cookie中取出三段串,反序列化解密放到session中
save_session:请求走了,把session字典中的值,序列化加密,放到cookie中
# open_session:请求来了执行
def open_session(self, app, request) :
s = self.get_signing_serializer(app)
if s is None:
return None
# val 就是取出的三段:eyJhZ2UiOiIxOSIsIm5hbWUiOiJscXoifQ.Y5ac9g.vOomQFqFuaqXWqRQhvSNyc61UIk
val = request.cookies.get('session')
if not val:
return self.session_class()
max_age = int(app.permanent_session_lifetime.total_seconds())
try:
data = s.loads(val, max_age=max_age)
return self.session_class(data)
except BadSignature:
return self.session_class()
# 请求走了,执行save_session
def save_session(self, app, session, response):
name = self.get_cookie_name(app)
domain = self.get_cookie_domain(app)
path = self.get_cookie_path(app)
secure = self.get_cookie_secure(app)
samesite = self.get_cookie_samesite(app)
httponly = self.get_cookie_httponly(app)
if not session: # 如果视图函数放了,不为空 session['name']='lqz'
if session.modified: #
response.delete_cookie(
name,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
httponly=httponly,
)
return
if session.accessed:
response.vary.add("Cookie")
if not self.should_set_cookie(app, session):
return
expires = self.get_expiration_time(app, session)
# 序列化---》加密了
val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore
# 三段:
response.set_cookie(
name, # session
val, # 三段:
expires=expires,
httponly=httponly,
domain=domain,
path=path,
secure=secure,
samesite=samesite,
)
"""
总结: session的执行流程
1.请求来的时候,会执行open_session--->取出cookie,判断是否为空,如果不为空,把它反序列化,解密--->字典--->转到session对象中----》视图函数
2.请求走的时候,会执行save_session---->把session转成字典---->序列化加密-->三段--->放到cookie中
"""
闪现
flash 翻译过来叫闪现
- 作用
访问a页面,出了错,重定向到了b页面,要在b页面线上a页面的错误信息在某个请求中放入值,另一个请求中取出,取出来后就没了
from flask import Flask, flash, get_flashed_messages
app = Flask(__name__)
app.secret_key = "asdfgghh"
@app.route("/login", methods=["GET", "POST"])
def login():
flash('我要', category="x1")
flash("必要", category='x2')
return "login"
@app.route("/flasks", methods=["GET", "POST"])
def flasks():
data = get_flashed_messages(category_filter=['x1', 'x2'])
print(data)
return "flask 界面"
if __name__ == "__main__":
app.run()
使用方式
# 使用方式一
设置值:
flash('不好意思,没有权限看')
可以用多次
取值:取出的是一个列表
get_flashed_messages()
# 使用方式二:分类设置和获取
设置值:
flash('钱钱钱',category='lqz')
flash('666',category='c1')')
可以用多次
取值:取出的是一个列表
errors = get_flashed_messages(category_filter=['lqz']) # 按分类取值
补充异步
# 异步框架 FastAPi
async def index():
print('sdfasd')
a++
await xxx # io操作
async def goods():
pass
# 框架之前的web框架,开启进程,线程---》一条线程会运行多个协程函数----》协程函数中遇到io,读到await关键字,就会切换到别的协程函数
# 一旦使用了异步,以后所有的模块,都要是异步
-pymysql :同步的
-redis :同步
-aiomysql:异步
-aioredis:异步
-在fastapi或sanic中,要操作mysql,redis要使用异步的框架,否则效率更低
-django 3.x 以后页支持async 关键字
-没有一个特别好异步的orm框架
-sqlalchemy在做
-tortoise-orm
https://tortoise-orm.readthedocs.io/en/latest/index.html
# aiomysql
import asyncio
import aiomysql
loop = asyncio.get_event_loop()
async def test_example():
conn = await aiomysql.connect(host='127.0.0.1', port=3306,
user='root', password='', db='mysql',
loop=loop)
cur = await conn.cursor()
await cur.execute("SELECT Host,User FROM user")
print(cur.description)
r = await cur.fetchall()
print(r)
await cur.close()
conn.close()
loop.run_until_complete(test_example())
# aioredis
import aioredis
import asyncio
class Redis:
_redis = None
async def get_redis_pool(self, *args, **kwargs):
if not self._redis:
self._redis = await aioredis.create_redis_pool(*args, **kwargs)
return self._redis
async def close(self):
if self._redis:
self._redis.close()
await self._redis.wait_closed()
async def get_value(key):
redis = Redis()
r = await redis.get_redis_pool(('127.0.0.1', 6379), db=7, encoding='utf-8')
value = await r.get(key)
print(f'{key!r}: {value!r}')
await redis.close()
if __name__ == '__main__':
asyncio.run(get_value('key')) # need python3.7
请求扩展(7个装饰器)
在请求进入视图函数之前,执行一些代码
请求出了视图函数以后,执行一些代码
类似于django的中间件完成的功能
1.before_request
用before_request装饰的函数是执行响应函数之前执行,如果有多个before_request他会自上而下按照顺序执行
如果before_request有返回值,那后面的before_request都不会执行,且响应函数也不会执行
# 基于它做用户登录认证
@app.before_request
def process_request(*args,**kwargs):
if request.path == '/login':
return None
user = session.get('user_info')
if user:
return None
return redirect('/login')
2.after_request
after_request是在请求从视图函数走之后执行的,要有参数,和返回值,参数就是response对象,返回值也必须是resposne对象,
session,request 照常使用
@app.after_request
def process_response1(response):
print('process_response1 走了')
return response
3.before_first_request
before_first_request项目启动后,第一次访问会执行,以后再也不执行了
可以理解为全局第一次的请求钩子方法,在一次服务启动期间,只可使用一次
可以做一些初始化的操作
@app.before_first_request
def first():
pass
4.teardown_request
teardown_request每一个请求之后绑定一个函数,即使遇到了异常,每个请求走,都会执行,记录错误日志
参数代表着抛出的错误
@app.teardown_request
def ter(e): # e有值是错误的信息
pass
5.errorhandler
errorhandler路径不存在时404,服务器内部错误500,并返回对应的错误页面
@app.errorhandler(404)
def error_404(arg):
print('404会执行我')
return "404错误了"
return render_template('404.html')
@app.errorhandler(500) # debug为False请情况下才能看到
def error_500(arg):
print('500会执行我')
return "服务器内部错误"
6.template_global
template_global全局的标签, 在任意的html页面中就可以直接使用, 不需要在render_template中传递参数以后才能使用了
@app.template_global()
def sb(a1, a2):
return a1 + a2
# html中直接使用
{{ sb(1,2) }}
7.template_filter
template_filter过滤器
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
# html中直接使用 (django中的过滤器最多只可以传递两个参数)
{{ 1|db(2,3) }} # 其中1传给a1 2传给a2 3传个a3
蓝图
blueprint对目录进行区分,因为之前的代码都写在同一个py文件中
后期肯定要分到多个py文件中
蓝图就是为了划分目录的
使用步骤
-
1.在不同的view的py文件中,定义蓝图
-
2.在app对象中,注册蓝图
-
3.使用蓝图,注册路由,注册请求扩展
不用蓝图划分目录
目录结构
flask_blueprint
static # 静态文件存放位置
templates # 模板存放位置
user.html # 用户html页面
views # 视图函数的py文件
__init__.py # 里面定义了Flask的app对象
goods.py # 商品相关视图
user.py # 用户相关视图
main.py # 启动文件

蓝图小型项目
目录结构
flask_blueprint_little # 项目名
src # 项目代码所在路径
__init__.py # app对象创建的地方
templates # 模板
user.html # 用户相关模板
static # 静态文件
views # 视图函数存放位置
user.py # 用户相关视图
order.py # 订单相关视图
manage.py # 启动文件

蓝图大型项目
项目目录
flask_blurprint_big # 项目名字
src # 项目代码所在位置
__init__.py # src的init,falsk,app实例化
settings.py # 配置文件
admin # 类似于django的admin app
__init__.py # 蓝图初始化
template # admin相关模板
backend.html
static # 静态文件
xx.jpg
views.py # 视图层
models.py # models层,后期咱们表模型
api # 类似于django的admin app
__init__.py # 蓝图初始化
template # api相关模板
static # 静态文件
models.py # models层,后期咱们表模型
views.py # 视图层
manage.py # 启动文件

posted on
浙公网安备 33010602011771号