目录

1.HTTP的会话控制

2.Cookie

3.Session

4.请求钩子

5.捕获错误

6.上下文:context

7.Flask-Script

1.HTTP的会话控制

1.什么是会话控制?

所谓的会话,就是客户端浏览器和服务端网站之间一次完整的交互过程.

会话的开始是在用户通过浏览器第一次访问服务端网站开始.

会话的结束时在用户通过关闭浏览器以后,与服务端断开.

所谓的会话控制,就是在客户端浏览器和服务端网站之间,进行多次http请求响应之间,记录、跟踪和识别用户的信息而已。

2.会话控制出现的原因

因为 http 是一种无状态协议,浏览器请求服务器是无状态的。

无状态:指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。

无状态原因:浏览器与服务器是使用 socket 套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的 socket 连接,而且服务器也会在处理页面完毕之后销毁页面对象。

3.会话控制的应用场景

有时需要保持下来用户浏览的状态,比如用户是否登录过,浏览过哪些商品等

实现状态保持主要有两种类型:

  • 在客户端存储信息使用url Cookietoken令牌[jwt.csrf,oauth]

  • 在服务器端存储信息使用Session

2.Cookie

1.Cookie是由服务器端生成,发送给客户端浏览器,浏览器会将Cookie的key/value保存,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。Cookie的key/value可以由服务器端自己定义。

2.使用场景: 登录状态, 浏览历史, 网站足迹,购物车 [不登录也可以使用购物车]

3.Cookie是存储在浏览器中的一段纯文本信息,建议不要存储敏感信息如密码,因为电脑上的浏览器可能被其它人使用

4.Cookie基于域名安全,不同域名的Cookie是不能互相访问的

如访问luffy.com时向浏览器中写了Cookie信息,使用同一浏览器访问baidu.com时,无法访问到luffy.com写的Cookie信息

5.浏览器的同源策略针对cookie也有限制作用.

6.当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器,所以在request中可以读取Cookie信息

1.设置cookie

设置cookie需要通过flask的Response响应对象来进行设置,由响应对象会提供了方法set_cookie给我们可以快速设置cookie信息。

@app.route("/set_cookie")
def set_cookie():
"""设置cookie"""
response = make_response("ok")
# 格式:response.set_cookie(key="变量名",value="变量值",max_age="有效时间/秒")
response.set_cookie("username","xiaoming",100)
"""如果cookie没有设置过期时间,则默认过期为会话结束过期"""
"""cookie在客户端中保存时,用一个站点下同变量名的cookie会覆盖"""
response.set_cookie("age","100") return response

2.获取cookie

@app.route("/get_cookie")
def get_cookie():
"""获取cookie"""
print(request.cookies)
print(request.cookies.get("username"))
print(request.cookies.get("age"))
"""打印效果:
{'username': 'xiaoming'}
"""
return ""

3.删除cookie

@app.route("/del_cookie")
def del_cookie():
"""删除cookie"""
response = make_response("ok")
# 把对应名称的cookie设置为过期时间(0s),则可以实现删除cookie
response.set_cookie("username","",0)
return response

3.Session

session相关配置项文档:https://dormousehole.readthedocs.io/en/latest/config.html?highlight=session_cookie_path

1.对于敏感、重要的信息,建议要存储在服务器端,不能存储在浏览器中,比如用户名、余额、等级、验证码等信息

2.在服务器端进行状态保持的方案就是Session

3.Session依赖于Cookie,session的ID一般默认通过cookie来保存到客户端。

4.flask中的session需要加密,所以使用session之前必须配置SECRET_KEY选项,否则报错.

5.session的有效期默认是会话期,会话结束了,session就废弃了。

6.如果将来希望session的生命周期延长,可以通过修改cookie中的sessionID来完成配置。

1.设置session

from flask import Flask, make_response, request,session

app = Flask(__name__)

class Config():
# flask中的session需要加密,所以使用session之前必须配置SECRET_KEY选项,否则报错.
SECRET_KEY = "123456asdadad"
DEBUG = True app.config.from_object(Config) @app.route("/set_session")
def set_session():
"""设置session"""
"""与cookie不同,session支持python基本数据类型作为值"""
session["username"] = "xiaohuihui"
session["info"] = {
"age":11,
"sex":True,
} return "ok" if __name__ == '__main__':
app.run(debug=True)

2.获取session

@app.route("/get_session")
def get_session():
"""获取session"""
print( session.get("username") )
print( session.get("info") )
return "ok"

3.删除session

@app.route("/del_session")
def del_session():
"""删除session"""
try:
del session["username"]
# session.clear() # 删除所有
except:
pass
return "ok"

Tip:如何查看当前flask默认支持的所有配置项

from flask import Flask, make_response, request,session

app = Flask(__name__)

class Config():
SECRET_KEY = "123456asdadad"
DEBUG = True app.config.from_object(Config) # 查看当前flask默认支持的所有配置项
print(app.config) # 下面是flask默认支持的所有配置项
"""
<Config {
'DEBUG': False,
'TESTING': False,
'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None,
'SECRET_KEY': None,
'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31),
'USE_X_SENDFILE': False,
'LOGGER_NAME': '__main__',
'LOGGER_HANDLER_POLICY': 'always',
'SERVER_NAME': None,
'APPLICATION_ROOT': None,
'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None,
'SESSION_COOKIE_PATH': None,
'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False,
'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None,
'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200),
'TRAP_BAD_REQUEST_ERRORS': False,
'TRAP_HTTP_EXCEPTIONS': False,
'EXPLAIN_TEMPLATE_LOADING': False,
'PREFERRED_URL_SCHEME': 'http',
'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True,
'JSONIFY_PRETTYPRINT_REGULAR': True,
'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None
"""

4.请求钩子

在客户端和服务器交互的过程中,有些准备工作或扫尾工作需要处理,比如:

  • 在请求开始时,建立数据库连接;

  • 在请求开始时,根据需求进行权限校验;

  • 在请求结束时,指定数据的交互格式;

为了让每个视图函数避免编写重复功能的代码,Flask提供了通用设置的功能,即请求钩子。

请求钩子是通过装饰器的形式实现,Flask支持如下四种请求钩子:

  • before_first_request

    • 在处理第一个请求前执行[项目初始化时的钩子]

  • before_request

    • 在每次请求前执行

    • 如果在某修饰的函数中返回了一个响应,视图函数将不再被调用 ***

  • after_request

    • 如果没有抛出错误,在每次请求后执行

    • 接受一个参数:视图函数作出的响应

    • 在此函数中可以对响应值在返回之前做最后一步修改处理

    • 需要将参数中的响应在此参数中进行返回

  • teardown_request:

    • 在每次请求后执行

    • 接受一个参数:错误信息,如果有相关错误抛出

    • 需要设置flask的配置DEBUG=False,teardown_request才会接受到异常对象。

from flask import Flask,make_response

app = Flask(__name__)

@app.before_first_request
def first_request():
print("1. 项目启动以后,首次被请求时,会自动执行[项目全局初始化工作]") @app.before_request
def before_request():
print("2. 每次客户端请求时,都会自动执行, 常用于记录访问日志,进行权限判断,身份识别,访问限流...") @app.after_request
def after_request(response):
print("4. 每次视图执行以后,会自动执行")
# after_request执行以后,必须要返回结果给客户端!!
return response @app.teardown_request
def teardown_request(exc):
print("5. after_request完成以后,如果有发生异常,在关闭DEBUG模式的情况下可以接受异常对象,进行异常的记录,异常通知")
print(exc) @app.route("/")
def set_session():
print("3. 视图执行了.......")
return "ok" if __name__ == '__main__':
app.run(debug=False)

第1次请求时打印:

1. 项目启动以后,首次被请求时,会自动执行[项目全局初始化工作]
2. 每次客户端请求时,都会自动执行, 常用于记录访问日志,进行权限判断,身份识别,访问限流...
3. 视图执行了.......
4. 每次视图执行以后,会自动执行
5. after_request完成以后,如果有发生异常,在关闭DEBUG模式的情况下可以接受异常对象,进行异常的记录,异常通知
None

第2次请求时打印:

2. 每次客户端请求时,都会自动执行, 常用于记录访问日志,进行权限判断,身份识别,访问限流...
3. 视图执行了.......
4. 每次视图执行以后,会自动执行
5. after_request完成以后,如果有发生异常,在关闭DEBUG模式的情况下可以接受异常对象,进行异常的记录,异常通知
None

5.捕获错误

flask中内置了app.errorhander提供给我们捕获异常,实现一些在业务发生错误时的自定义处理。

1. 通过http状态码捕获异常信息

2. 通过异常类进行异常捕获

  • errorhandler 装饰器

    • 注册一个错误处理程序,当程序抛出指定错误状态码的时候,就会调用该装饰器所装饰的方法

  • 参数:

    • code/exception – HTTP的错误状态码或指定异常类

1.比如统一处理状态码为500的错误给用户友好的提示:

@app.errorhandler(500)
def internal_server_error(e):
return '服务器搬家了'

2.捕获指定系统异常类

@app.errorhandler(ZeroDivisionError)
def zero_division_error(e):
return '除数不能为0'

3.也可以捕获自定义异常类

from flask import Flask

app = Flask(__name__)

"""加载配置"""
class Config():
DEBUG = True
app.config.from_object(Config) """捕获系统异常或者自定义异常"""
class APIError(Exception):
pass @app.route("/")
def index():
raise APIError("api接口调用参数有误!")
return "个人中心,视图执行了!!" @app.errorhandler(APIError)
def error_apierror(e):
return "错误: %s" % e if __name__ == '__main__':
app.run(host="localhost",port=8080)

6.上下文:context

执行上下文:即语境,语意,在程序中可以理解为在代码执行到某一行时,根据之前代码所做的操作以及下文即将要执行的逻辑,可以决定在当前时刻下可以使用到的变量,或者可以完成的事情。

Flask中上下文对象:相当于一个容器,保存了 Flask 程序运行过程中的一些信息[变量、函数、类与对象等信息]。

Flask中有两种上下文,请求上下文(request context)和应用上下文(application context)。

  1. application 指的就是当你调用app = Flask(__name__)创建的这个对象app

  2. request 指的是每次http请求发生时,WSGI server(比如gunicorn)调用Flask.__call__()之后,在Flask对象内部创建的Request对象;

  3. application 表示用于响应WSGI请求的应用本身,request 表示每次http请求;

  4. application的生命周期大于request,一个application存活期间,可能发生多次http请求,所以,也就会有多个request

1.请求上下文(request context)

思考:在视图函数中,如何取到当前请求的相关数据?比如:请求地址,请求方式,cookie等等

在 flask 中,可以直接在视图函数中使用 request 这个对象进行获取相关数据,而 request 就是请求上下文的对象,保存了当前本次请求的相关数据,请求上下文对象有:request、session

  • request

    • 封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。

  • session

    • 用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息。

注意!!!!:请求上下文提供的变量/属性/方法/函数/类与对象,只能在视图中或者被视图调用的地方使用

2.应用上下文(application context)

它的字面意思是 应用上下文,但它不是一直存在的,它只是request context 中操作当前falsk应用对象 app 的代理(人),所谓local proxy。它的作用主要是帮助 request 获取当前的flask应用相关的信息,它是伴 request 而生,随 request 而灭的。

应用上下文对象有:current_app,g

1.current_app

应用程序上下文,用于存储应用程序中的变量,可以通过current_app.name打印当前app的名称,也可以在current_app中存储一些变量,例如:

  • 应用的启动脚本是哪个文件,启动时指定了哪些参数

  • 加载了哪些配置文件,导入了哪些配置

  • 连接了哪个数据库

  • 有哪些可以调用的工具类、常量

  • 当前flask应用在哪个机器上,哪个IP上运行,内存多大

from flask import Flask,request,session,current_app,g

# 初始化
app = Flask(import_name=__name__) # 声明和加载配置
class Config():
DEBUG = True
app.config.from_object(Config) # 编写路由视图
@app.route(rule='/')
def index():
# 注意!!!!:应用上下文提供给我们使用的变量,也是只能在视图或者被视图调用的地方进行使用,
# 但是应用上下文的所有数据来源于于app,每个视图中的应用上下文基本一样
print(current_app.config) # 获取当前项目的所有配置信息
print(current_app.url_map) # 获取当前项目的所有路由信息 return "<h1>hello world!</h1>" if __name__ == '__main__':
# 运行flask
app.run(host="0.0.0.0")

2.g变量

g 作为 flask 程序全局的一个临时变量,充当者中间媒介的作用,我们可以通过它传递一些数据,g 保存的是当前请求的全局变量,不同的请求会有不同的全局变量,通过不同的thread id区别

from flask import Flask,request,session,current_app,g

# 初始化
app = Flask(import_name=__name__) # 声明和加载配置
class Config():
DEBUG = True
app.config.from_object(Config) @app.before_request
def before_request():
g.name = "root" def get_two_func():
name = g.name
print("g.name=%s" % name) def get_one_func():
get_two_func() # 编写路由视图
@app.route(rule='/')
def index():
# 请求上下文提供的变量/属性/方法/函数/类与对象,只能在视图中或者被视图调用的地方使用
# 请求上下文里面信息来源于每次客户端的请求,所以每个视图中请求上下文的信息都不一样
# print(session) # 应用上下文提供给我们使用的变量,也是只能在视图或者被视图调用的地方进行使用,
# 但是应用上下文的所有数据来源于于app,每个视图中的应用上下文基本一样
print(current_app.config) # 获取当前项目的所有配置信息
print(current_app.url_map) # 获取当前项目的所有路由信息
get_one_func()
return "<h1>hello world!</h1>" if __name__ == '__main__':
# 运行flask
app.run(host="0.0.0.0")

3.关于请求上下文和应用上下文的总结

由flask提供了2种不同的上下文对象给我们开发者获取项目或者客户端的信息

这些对象不需要我们进行实例化,由flask内部创建的
  1. 请求上下文: request, session
  2. 应用上下文: current_app, g

不管是请求上下文或者应用上下文都只能使用在视图范围内或者能被视图调用的地方

如果是视图以外地方使用,则会报错:
RuntimeError: Working outside of application context.

解决方案:
with app.app_context():
  print(g)

'''
请求上下文提供的变量/属性/方法/函数/类与对象,只能在视图中或者被视图调用的地方使用
请求上下文里面信息来源于每次客户端的请求,所以每个视图中请求上下文的信息都不一样
''' '''
应用上下文提供给我们使用的变量,也是只能在视图或者被视图调用的地方进行使用,
但是应用上下文的所有数据来源于于app,每个视图中的应用上下文基本一样
'''

7.Flask-Script

文档: https://flask-script.readthedocs.io/en/latest/

这个模块的作用可以让我们通过终端来控制flask项目的运行,类似于django的manage.py

安装命令:

pip install flask-script

1.启动终端脚本运行项目

from flask import Flask
from flask_script import Manager app = Flask(__name__) class Config():
DEBUG = True app.config.from_object(Config) # 注册终端脚本工具到app中
manager = Manager(app) @app.route("/")
def index():
return "ok" if __name__ == '__main__':
# 注意,这里不是app对象
manager.run() # 端口和域名不写,默认为127.0.0.1:5000
# python run.py runserver # 通过-h设置启动域名,-p设置启动端口
# python run.py runserver -h127.0.0.1 -p8888

2.自定义终端命令

如果我们想自定义终端命令,必须要遵从以下三点

1. 引入Command命令基类
2. 创建命令类必须直接或间接继承Command,并在内部实现run方法,同时如果有自定义的其他参数,则必须实现__init__
3. 使用flask_script应用对象manage.add_command对命令类进行注册,并设置调用终端别名。

from flask import Flask
from flask_script import Manager, Command, Option # 1.引入command命令基类
app = Flask(__name__)
class Config():
DEBUG = True
app.config.from_object(Config) """基于flask_script创建自定义终端命令"""
class HelloCommand(Command): # 2.1 创建命令类必须直接或间接继承Command
"""命令相关的注释"""
option_list = [
Option("--name","-n",help="名称"),
Option("--num","-m",help="数量"),
]
def run(self,name,num): # 2.2 在自定义终端命令内部实现run方法
print("name=%s" % name)
print(num)
print("命令执行了!!!") # 注册终端脚本工具到app中
manager = Manager(app)
manager.add_command("hello", HelloCommand) # 3.使用flask_script应用对象manage.add_command对命令类进行注册,并设置调用终端别名。 @app.route("/")
def index():
return "ok" if __name__ == '__main__':
manager.run() # 运行该程序
# python run.py hello -n=hahaha -m=qiqiqi

运行结果:

3.自定义脚手架命令

from flask import Flask
from flask_script import Manager, Command, Option # 1.引入Command命令基类 app = Flask(__name__) class Config():
DEBUG = True
app.config.from_object(Config) manager = Manager(app)
import os
class BluePrintCommand(Command): # 2.1 创建命令类直接或间接继承Command
option_list = [
Option("--name","-n",help="蓝图名称")
] def run(self,name=None): # 2.2 在命令类内部实现run方法
if name is None:
print("蓝图名称不能为空!")
return
if not os.path.isdir(name):
os.mkdir(name)
open("%s/views.py" % name,"w")
open("%s/models.py" % name,"w")
with open("%s/urls.py" % name,"w") as f:
f.write("""from . import views
urlpatterns = [ ]
""") manager.add_command("blue", BluePrintCommand) # 3.使用应用对象.add_command对命令类进行注册,并设置调用终端别名 @app.route("/")
def index():
return "ok" if __name__ == '__main__':
manager.run() # 运行程序
# python run.py blue -n=users

运行结果:

day93:flask:的更多相关文章

  1. flask+sqlite3+echarts2+ajax数据可视化

    前提: 准备Python + Flask+Sqlite3的平台环境(windows系统) 前面一节介绍flask怎么安装了,剩下sqlite3下载后解压,然后环境变量添加解压路径就行了 附加下载地址: ...

  2. flask+sqlite3+echarts2+ajax数据可视化报错:UnicodeDecodeError: 'utf8' codec can't decode byte解决方法

    flask+sqlite3+echarts2+ajax数据可视化报错: UnicodeDecodeError: 'utf8' codec can't decode byte 解决方法: 将 py文件和 ...

  3. Windows下快速安装Flask的一次经历

    前提: 1.已安装python版本(一般都是2.X) 2.已安装easy_install python安装,记得配置Python的环境变量,例如:我的直接在Path上加 G:\Python 验证安装P ...

  4. 使用Flask设计带认证token的RESTful API接口[翻译]

    上一篇文章, 使用python的Flask实现一个RESTful API服务器端  简单地演示了Flask实的现的api服务器,里面提到了因为无状态的原则,没有session cookies,如果访问 ...

  5. 使用python的Flask实现一个RESTful API服务器端[翻译]

    最近这些年,REST已经成为web services和APIs的标准架构,很多APP的架构基本上是使用RESTful的形式了. 本文将会使用python的Flask框架轻松实现一个RESTful的服务 ...

  6. python flask (一)

    from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World ...

  7. flask源码分析

    本flask源码分析不间断更新 而且我分析的源码全是我个人觉得是很beautiful的 1 flask-login 1.1 flask.ext.login.login_required(func),下 ...

  8. Python flask 基于 Flask 提供 RESTful Web 服务

    转载自 http://python.jobbole.com/87118/ 什么是 REST REST 全称是 Representational State Transfer,翻译成中文是『表现层状态转 ...

  9. Python flask @app.route

    转载自 http://python.jobbole.com/80956/ 下面是Flask主页给我们的第一个例子,我们现在就由它入手,深入理解“@app.route()”是如何工作的.         ...

随机推荐

  1. 【传递闭包】HDU 2157 How many ways??

    UPD:现在才发现本题是个传递闭包 题目内容 春天到了,HDU校园里开满了花,姹紫嫣红,非常美丽. 葱头是个爱花的人,看着校花校草竞相开放,漫步校园,心情也变得舒畅. 为了多看看这迷人的校园,葱头决定 ...

  2. php中,posix_getpid() 和 getmypid() 有什么不同

    getmypid:windows 和 linux都可以用posix_getpid:仅linux可以用

  3. PHPStorm注释缩进问题

    以下是让强迫症很难受的注释格式 以下几步即可解决强迫症的烦恼 1.点击File 2.点击setting 3.按照以下几步走 4.按照以下几步走   5.最后效果如下

  4. C# URL编码

    #region URL编码 /// <summary> /// URL编码 /// </summary> /// <param name="str"& ...

  5. Hugo+Github 搭建个人博客(Windows环境下)

    目录 Hugo+Github 搭建个人博客(Windows环境下) 1.前言 2.Differences 2.1 https vs SSH 2.2 新建的github的仓库名必须为 用户名+githu ...

  6. Linux命令之date +%F

    date命令显示当前日期 date +%F显示当前日期 [10:02:52 root@C8[ 2020-06-16DIR]#touch `hostname`_`date +%F`.log [10:03 ...

  7. docker在win7下的使用

    1,安装 win7下需要安装docker-toolbox,然后通过Docker Quickstart Terminal运行 2,加速 直接pull的话是拉取的docker hub上的镜像,速度非常慢, ...

  8. vue3.0 的 Composition API 的一种使用方法

    网上讨论的文章已经很多了,这里举一个简单的例子来讨论一下 Composition API 的用法,具体问题才好具体讨论嘛. 假如我们要做一个论坛的讨论列表和分页,以前是把需要的数据都放在data里面, ...

  9. D. Rescue Nibel! 解析(思維、組合、離散化、差分)

    Codeforce 1420 D. Rescue Nibel! 解析(思維.組合.離散化.差分) 今天我們來看看CF1420D 題目連結 題目 給你\(n\)個區間,求有幾種方法使得\(k\)個區間的 ...

  10. ERP收付款的操作与设计--开源软件诞生22

    赤龙ERP收款付款讲解--第22篇 用日志记录"开源软件"的诞生 [进入地址 点亮星星]----祈盼着一个鼓励 博主开源地址: 码云:https://gitee.com/redra ...