什么是上下文    上下文相当于一个容器,保存了 Flask 程序运行过程中的一些信息。
Flask 中有两种上下文,请求上下文(request 和 session )和应用上下文(current_app和g)。

常用重点:

1.上下文处理器应该返回一个字典,字典中的key会被模板中当成变量来渲染

2.上下文处理器返回的字典,在所有页面中都是可以使用的

3.被这个装饰器修饰的钩子函数,必须要返回一个字典,即使为空也要返回。

上下文举例

开发中我们常常需要获取当前时间进行显示, 这个时间可以是应用的全局变量.  借助context_processor我们可以让所有自定义变量在模板中可见,如下面的代码,我们将 online_time  作为一个变量在所有模板中可见:
上下文应用处理器也就是把全局变量进行封装然后展现到模板当中

# 上下文全局处理器
import datetime@admin.context_processor
def tpl_extra():data = dict(online_time=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))return data然后在html页面中使用{{online_time}}即可

上下文

请求上下文(request context)

Flask从客户端收到请求时,要让视图函数能访问一些对象,这样才能处理请求。请求对象是一个很好的例子,它封装了客户端发送的HTTP请求。

要想让视图函数能够访问请求对象,一个显而易见的方式是将其作为参数传入视图函数,不过这会导致程序中的每个视图函数都增加一个参数,除了访问请求对象,如果视图函数在处理请求时还要访问其他对象,情况会变得更糟。为了避免大量可有可无的参数把视图函数弄得一团糟,Flask使用上下文临时把某些对象变为全局可访问。

request 和 session 都属于请求上下文对象。
- request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get(‘user’),获取的是get请求的参数。
- session:用来记录请求会话中的信息,针对的是用户信息。举例:session[‘name’] = user.id,可以记录用户信息。还可以通过session.get(‘name’)获取用户信息。

当调用app = Flask(name)的时候,创建了程序应用对象app;
request 在每次http请求发生时,WSGI server调Flask.call();然后在Flask内部创建的request对象;
app的生命周期大于request,一个app存活期间,可能发生多次http请求,所以就会有多个request。
最终传入视图函数,通过return、redirect或render_template生成response对象,返回给客户端。

请求上下文举例:

from flask import request, Flaskapp = Flask(__name__)@app.route('/index')
def index():user_agent = request.headers.get("User-Agent")return "<p>Your browser is %s</p>" % user_agentif __name__ == '__main__':app.run(debug=True)

运行结果:

应用上下文 (application context)

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

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

current_app

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

  • 应用的启动脚本是哪个文件,启动时指定了哪些参数
  • 加载了哪些配置文件,导入了哪些配置
  • 连了哪个数据库
  • 有哪些public的工具类、常量
  • 应用跑再哪个机器上,IP多少,内存多大

current_app.name

g变量

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

g.name='abc'

应用上下文程序示例:

from flask import Flask, current_appapp = Flask(__name__)@app.route("/index")
def index():return "hello %s" % current_app.nameif __name__ == '__main__':app.run(debug=True)

运行结果: 获取了程序名称

两者区别

请求上下文:保存了客户端和服务器交互的数据

应用上下文:flask 应用程序运行过程中,保存的一些配置信息,比如说程序名,数据库连接,应用信息等。

Werkzeug

首先,先向大家介绍一下什么是 werkzeug,Werkzeug是一个WSGI工具包,他可以作为一个Web框架的底层库。这里稍微说一下, werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等。

例如我最常用的 Flask 框架就是一 Werkzeug 为基础开发的,这也是我要解析一下 Werkzeug 底层的原因,因为我想知道 Flask 的实现逻辑以及底层控制。这篇文章没有涉及到 Flask 的相关内容,只是以 Werkzeug 创建一个简单的 Web 应用,然后以这个 Web 应用为例剖析请求的处理以及响应的产生过程。

下面我们以一个简短的例子开始,先看看怎么使用 werkzeug,然后再逐步刨析 werkzeug 的实现原理。

安装 werkzeug

我希望读者是在 virtualenv 环境中跟着我的步伐走得,如果你还不知道什么是 virtualenv,那么你可以在我的博客中搜索一下 virtualenv,然后先弄好,再继续,因为很可能因为一些库的冲突等问题导致你看不到本文中介绍的东西。

ok,下面开始安装 werkzeug,

1

pip install Werkzeug

这条命令下去,几秒钟之后你就可以使用 werkzeug 了。

一个简单地 web 服务器

接下来,我们就开始使用 werkzeug 来创建一个简单的 web 服务器,这个服务器就仅仅返回 “Hello Werkzeug”,没有其他内容。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

#!/usr/bin/env python

# encoding: utf-8

import os

from werkzeug.serving import run_simple

from werkzeug.wrappers import Request, Response

from werkzeug.wsgi import SharedDataMiddleware

class Shortly(object):

def dispatch_request(self, request):

return Response('Hello Werkzeug!')

def wsgi_app(self, environ, start_response):

request = Request(environ)

response = self.dispatch_request(request)

return response(environ, start_response)

def __call__(self, environ, start_response):

return self.wsgi_app(environ, start_response)

def create_app(with_static=True):

app = Shortly()

if with_static:

app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {

'/static': os.path.join(os.path.dirname(__file__), 'static')

})

return app

if __name__ == '__main__':

app = create_app()

run_simple('127.0.0.1', 6666, app, use_debugger=True, use_reloader=True)

这段代码就实现了我说的功能,那么我们就来看看这段代码是怎么运作的?

首先,一切都回到最开始的地方开始,从 main 开始看起,可以发现 main 是非常简单地,只有一个初始化函数,然后就调用了 werkzeug 的 run_simple 函数。okay,我们可以发现这个 app 其实是一个 Shortly 对象,这个类就只实现了 3 个方法,一个是 dispatch_request, wsig_app, call ,就这么简单了,那我们就知道了,关键的代码都不是这些,应该是 run_simple.

WSGI

在介绍Werkzeug之前,先介绍一下 WSGI(Python Web Server Gateway Interface),它为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。这是一个规范,描述了web server如何与web application交互、web application如何处理请求,该规范的具体描述在PEP3333,强烈推荐先阅读 PEP3333 再回头来阅读本文。

WSGI 分为两个部分:

  • Server/Gateway: 即是HTTP Server, 负责从客户端(Nnginx、apache、IIS)接收请求,将 request 转发给 application, 并将 application(可能是个Flask应用) 返回的response 返回给客户端
  • Application/Framework: 一个python web 应用或 web 框架接收由 server 转发的request,处理请求,并将处理结果返回给 server

可以通过下面两张图片来梳理一下它们之间的调用关系:

Werkzeug

werkzeug 提供了 python web WSGI 开发相关的功能:

  • 路由处理:如何根据请求 URL 找到对应的视图函数
  • request 和 response 封装: 提供更好的方式处理request和生成response对象
  • 自带的 WSGI server: 测试环境运行WSGI应用

请求上下文\实现原理

Flask是一个基于WerkZeug实现的框架,因此Flask的App Context和Request Context是基于WerkZeug的Local Stack的实现。
这两种上下文对象类定义在flask.ctx中,ctx.push会将当前的上下文对象压栈压入flask._request_ctx_stack中,这个_request_ctx_stack同样也是个Thread Local对象,也就是在每个线程中都不一样,上下文压入栈后,再次请求的时候都是通过_request_ctx_stack.top在栈的顶端取,所取到的永远是属于自己线程的对象,这样不同线程之间的上下文就做到了隔离。请求结束后,线程退出,ThreadLocal本地变量也随即销毁,然后调用ctx.pop()弹出上下文对象并回收内存。

werkzeug.security模块加密

参考:利用Flask中的werkzeug.security模块加密

若将密码以明文的方式保存在数据库中是不安全的,可以使用一些如MD5的方式加密,但像这种加密方式也是存在安全隐患的,这里我们来学习一下利用Flask中的werkzeug.security模块加密
1、这种加密方式的原理:加密时混入一段“随机”字符串(盐值)再进行哈希加密。即使
密码相同,如果盐值不同,那么哈希值也是不一样的。现在网站开发中主要是运
用这种加密方法。
2、这个模块主要是用到了两个函数:

  • 密码生成函数:generate_password_hash;
  • 密码验证函数:check_password_hash;

3、密码生成函数:generate_password_hash
(1)函数定义

werkzeug.security.generate_password_hash(password, method='pbkdf2:sha1', salt_length=8)

参数说明:

  • password: 明文密码;
  • method:哈希加密的方法(需要hashlib库支持的),格式为pdpdf2:[:iterations];
    method:哈希的方式,一般为SHA1;
    iterations:(可选参数)迭代次数,默认为1000;

-slat_length: 盐值的长度,默认为8。
(2)密码生成示例:

from werkzeug.security import  generate_password_hash,check_password_hash
print (generate_password_hash('123456'))
print (generate_password_hash('123456'))

输出:

pbkdf2:sha1:1000$0yy56h3w$ae1030bd575e95a1b7066120d6b2381ae01f678d
pbkdf2:sha1:1000$Roji1qH7$c6867df485c8c9ff094025e1bf779cbf570dcbf1

因为盐值是随机的,所以就算是相同的密码,生成的哈希值也不会是一样的。
4、码验证函数:check_password_hash
(1)函数定义

werkzeug.security.check_password_hash(pwhash, password)

参数说明:

  • pwhash:generate_password_hash生成的哈希字符串(即加密后的密码);
  • password:需要验证的明文密码;

check_password_hash函数用于验证经过generate_password_hash哈希的密码,若密码匹配,则返回真,否则返回假。
(2)密码验证示例:

from werkzeug.security import  generate_password_hash,check_password_hashpwhash = "pbkdf2:sha1:1000$Roji1qH7$c6867df485c8c9ff094025e1bf779cbf570dcbf1"
print (check_password_hash(pwhash,'123456'))

输出:True

附录:

进一步学习参考:

Python 工具包 werkzeug 初探

Werkzeug中文文档_w3cschool

python Flask 10 Flask请求上下文管理werkzeug相关推荐

  1. Python 21 Flask(二)上下文管理详解

    上下文管理 对于上下文管理我没有找到明确的定义,但是经过源码流程的学习后,我觉得所谓的上下文管理应该就是Flask对请求和应用相关数据的一种处理方式,它不是像Django一样通过参数的传导,而是创建了 ...

  2. flask中的请求上下文

    2019独角兽企业重金招聘Python工程师标准>>> 根据前一篇应用上下文可知,请求上下文的作用域是发生在请求到来之后. 如有一个应用函数返回用户应该跳转到的URL.想象它总是会跳 ...

  3. Web框架——Flask系列之请求上下文与应用上下文请求钩子Flask-Script扩展命令行(十七)

    一.请求上下文和应用上下文 请求上下文(request context) request和session都属于请求上下文对象. 应用上下文(application context) current_a ...

  4. python sqlite3事务_python使用上下文管理器实现sqlite3事务机制

    如题,本文记录如何使用python上下文管理器的方式管理sqlite3的句柄创建和释放以及事务机制. 1.python上下文管理(with) python上下文管理(context),解决的是这样一类 ...

  5. python实现可以被with上下文管理的类或函数

    开始之前先明确一下with机制 1.类包函数__ enter__()和__exit__()函数,即是可以被上下文管理的类 __enter__用来执行with时的方法,__exit__返回对象给with ...

  6. python上下文管理关键字_详解 Python 中的 with 与 上下文管理器

    with 这个关键字,对于每一学习Python的人,都不会陌生. 操作文本对象的时候,几乎所有的人都会让我们要用 with open ,这就是一个上下文管理的例子.你一定已经相当熟悉了,我就不再废话了 ...

  7. 读书笔记:《流畅的Python》第15章 上下文管理器和else块

    # 第15章 上下文管理器和else块""" 本章内容提要:with语句和上下文管理器for while try语句的else子句 """# ...

  8. python高级学习笔记Day04--01 上下文管理器,生成器,深拷贝,浅拷贝,正则表达式

    with语句 简单又安全 with open('1.txt','w') as f: f.write('hello,world') 上下文管理器 with语句之所以这么强大,背后是由上下文管理器做支撑的 ...

  9. Flask的上下文管理机制

    前引 在了解flask上下文管理机制之前,先来一波必知必会的知识点. 面向对象双下方法 首先,先来聊一聊面向对象中的一些特殊的双下划线方法,比如__call__.__getattr__系列.__get ...

最新文章

  1. boost::bind的使用
  2. python基础---面向过程编程
  3. select下拉框赋值和取值
  4. JAVA中的方法和构造方法有什么区别
  5. 【Python数据结构】 抽象数据类型 Python类机制和异常
  6. 面试必会系列 - 1.7 JVM 内存模型
  7. CMD命令之BAT脚本路径信息
  8. 关于id Tech5的MegaTexture技术
  9. 你试过一个人旅游吗?去了哪里?
  10. linux命令cd回退_Linux命令一
  11. Hibernate 注解方式
  12. VBScript基础
  13. 《大般涅槃经》略释 净慧法师
  14. Testin云测:深耕企业应用服务
  15. 阿里云mysql导出表_mysql导出数据库表
  16. [MRI]核磁共振头线圈和体线圈
  17. youtube字幕下载
  18. ti ds90ub953 与ds90ub954 、ds90ub933的调试总结
  19. .msi文件安装报错
  20. 51单片机学习——中断

热门文章

  1. syn泛洪 过滤_SYN泛洪攻击详解
  2. ubuntu 8.04玩魔兽争霸
  3. 老板电器携手华为HarmonyOS创新升级中国厨房新理念
  4. pycharm能不能编写Java_使用Pycharm编写第一个Python程序
  5. arcos的matlab定义,基于MATLAB编程软的齿轮设计
  6. SUS系统可用性量表
  7. Eric S. Raymond:如何成为一名黑客
  8. 内存优化(一)浅谈内存优化
  9. 例题5.20 秦始皇修路 LA5713
  10. 冯小刚回应质疑:中国没大师 谁都别装!