什么是Werkzeug
上一节介绍了什么是WSGI,这一节我们看看Werkzeug
按照官方的说法,Werkzeug(源自德语,工具的意思)是一个WSGI工具库,它开始于一个适用于WSGI的多样化的工具集,后来发展成了现在非常流行的WSGI工具库。Werkzeug可以在程序中单独使用,也作为许多Python Web框架的底层库,例如现在非常流行的Flask Web框架。
Werkzeug的基本功能
正如官方的说法,Werkzeug提供了非常丰富的功能,但是其功能总的可分为两个方面:开发测试方面的功能和其用于Web程序中的工具函数及工具类
开发测试方面
一、Werkzeug提供了一个简易的开发用服务器
二、Werkzeug提供了一些测试工具,如Client类、EnvironBuilder类。
三、Werkzeug提供了Debug的工具,提供了可用于Debug的中间件。当程序出错时,并不会返回500错误,而是显示程序出错的地方以及出错的原因,这就为程序的开发提供了方便。
工具方面
Werkzeug主要提供了如下几种工具
一、请求和相应对象。
提供了Request和Response。Request可以包装WSGI服务器传入的environ参数,并对其进行进一步的解析,以使我们更容易的使用请求中的参数。Response可以根据传入的参数,来发起一个特定的响应。你可以认为Response是你可以创建的另一个标准的WSGI应用,这个应用可以根据你传入的参数,来帮你做发起响应这件事。
from werkzeug.wrappers import Request, Response
def application(environ, start_response):
request = Request(environ)
response = Response("Hello %s!" % request.args.get('name', 'World!'))
return response(environ, start_response)
二、路由解析。
Werkzeug提供了强大的路由解析功能。比如Flask框架中经常用到的Rule、Map类等。
如下面一个程序。
from werkzeug.routing import Map, Rule, NotFound, RequestRedirect
url_map = Map([
Rule('/', endpoint='blog/index'),
Rule('/<int:year>/<int:month>/<int:day>/', endpoint='blog/archive'),
Rule('/about', endpoint='blog/about_me'),
Rule('/feeds/<feed_name>.rss', endpoint='blog/show_feed')
])
def application(environ, start_response):
urls = url_map.bind_to_environ(environ)
try:
endpoint, args = urls.match()
except HTTPException, e:
return e(environ, start_response)
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Rule points to %r with arguments %r' % (endpoint, args)]
我们创建了一个Map类实例url_map来保存一系列的URL规则。并且给它传递了一个Rule对象的列表。其中,每个Rule对象都包含两个参数:一个字符串和endpoint。字符串代表了URL匹配的规则(也叫路由规则),endpoint(也叫端点)代表了该路由规则对应的视图函数。即当对一个URL匹配成功后,便可获取到它对应的视图函数。不同的规则可以对应相同的endpoint,但是必须有不同的参数用于URL的构建,不能产生歧义,类似于函数的重载。
在application函数中,我们使用Map的bind_to_environ方法将url_map与environ绑定,这会返回给我们一个新的MapAdapter对象,这个对象可用于URL的匹配。随后,我们调用MapAdapter对象中的match()方法,获取当前请求的URL匹配到的endpoint和其参数信息,最后,我们用获取到的endpoint和参数信息发起一个响应。
用于匹配URL的路由规则字符串是由基本的URL加上占位符组成的。
例如Rule('/pages/<path:page>'),尖括号中,冒号后面为变量名,前面为变量的类型。path类型表示只匹配路径。这里的path也可以是int,表示匹配一个整型以及float等。
当不包含尖括号中的变量不写明类型时,如Rule('/pages/<page>'),这里的page可以匹配任何字符串,但是只能就受一个路径段,因此不能含有/。
更详细的规则还请参见文档
三、本地上下文
在许多Web程序中,本地上下文是个非常重要的概念。而实现本地上下文需要用到不同线程间数据的隔离。werkzeug.local中定义了Local、LocalStack和LocalProxy等类用于实现全局数据的隔离。
在Python中,我们可以使用thread locals来保证多线程状态下数据的隔离,但是这在Web程序中,却并不是很好使。
- 一是因为有些Web应用是使用协程实现的,无法保证数据的隔离。
- 二是即使使用的是线程,WSGI也不能保证每次请求使用的线程都是一个全新的线程,可能是一个之前请求的线程,而里面的数据也是原线程剩下的。
所以,Werkzeug给我们提供了Local这个更好用的解决工具。
下面是一个如何使用werkzeug.local例子:
from werkzeug.local import Local, LocalManager
local = Local()
local_manager = LocalManager([local])
def application(environ, start_response):
local.request = request = Request(environ)
...
application = local_manager.make_middleware(application)
可以看到,我们把一个Request对象赋值给了全局对象local.request,这样,我们就可以在全局范围内使用local.request,而且获取到的仅仅是当前请求的数据。因为Local对象不会在请求结束后自动清除本地上下文,所以这里我们需要使用LocalManager来管理。我们需要将管理的Local对象以列表的方式传给LocalManager,并在最后使用LocalManager的make_middleware方法为WSGI程序添加中间件,来使请求结束后自动清除本次请求的数据。
那么Local是如何实现的呢?其实很简单,在Local中,重写了__getattr__和__setattr__方法,使得在获取数据和存储数据之前,先获取到线程id(或协程id),以线程id(或协程id)为键,数据为值,存储在一个字典中。这样我们在操作数据的时候,操作的只会是当前线程(或协程)的数据,从而实现了数据隔离。感兴趣的同学可以查看一下文末Local的源码。
LocalStack对Local进行了封装,使其可以以栈的方式使用。如下:
>>> ls = LocalStack()
>>> ls.push(42)
>>> ls.top
42
>>> ls.push(23)
>>> ls.top
23
>>> ls.pop()
23
>>> ls.top
42
LocalProxy类用于实现werkzeug本地代理,将所有的操作转发给代理对象。如果你熟悉C++的话,你会发现这和C++的引用很像,但比引用更强大。使用方法如下:
from werkzeug.local import Local
l = Local()
# 以下是两个代理
request = l('request') # Local中实现了__call__方法,用于返回一个代理,具体可以查看文末Local的源码
user = l('user')
from werkzeug.local import LocalStack
_response_local = LocalStack()
# 这也是个代理
response = _response_local() # 同理,LocalStack返回的也是代理
除了以上创建代理的方式外,还可以手动创建一个代理
from werkzeug.local import Local, LocalProxy
local = Local()
request = LocalProxy(local, 'request')
如果你想拥有一个根据指定函数来返回不同的对象代理,也是支持的。
session = LocalProxy(lambda: get_current_request().session)
但我们为什么要使用代理呢。这里简单说一下,我们知道,一个变量被赋值后如果不重新赋值,它的值是不会改变的,那么这在程序的某些地方就会变得很不方便。但是如果使用代理的话,那么我们在使用这个变量的时候就能动态的获取到它所代理的对象的最新的值。
四、其他
除了上面三个方面外,Werkzeug还提供了很多工具,例如WSGI中间件、HTTP异常类、数据结构等。这里就不在一一详述,感兴趣的同学可以参考文档。
Local对象部分源码:
try:
from greenlet import getcurrent as get_ident
except ImportError:
try:
from thread import get_ident
except ImportError:
from _thread import get_ident
class Local(object):
__slots__ = ('__storage__', '__ident_func__')
def __init__(self):
object.__setattr__(self, '__storage__', {})
object.__setattr__(self, '__ident_func__', get_ident)
def __iter__(self):
return iter(self.__storage__.items())
def __call__(self, proxy):
"""Create a proxy for a name."""
return LocalProxy(self, proxy)
def __release_local__(self):
self.__storage__.pop(self.__ident_func__(), None) # 清除数据
def __getattr__(self, name):
try:
return self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
def __setattr__(self, name, value):
ident = self.__ident_func__()
storage = self.__storage__
try:
storage[ident][name] = value
except KeyError:
storage[ident] = {name: value}
def __delattr__(self, name):
try:
del self.__storage__[self.__ident_func__()][name]
except KeyError:
raise AttributeError(name)
参考:
本篇参考Werkzeug文档写成,如有错误或与文档不符的地方,还请以文档为准,也欢迎您反馈给我。
什么是Werkzeug的更多相关文章
- Werkzeug工具包学习-官方例子Shortly分析
为了学习werkzeug的wsgi框架工具,今天真对官网的例子进行调试运行.涉及到了werkzeug工具包,jinja2前端模版,以及redis内存库,之后可以灵活定制自己主页.再次,作以记录. 首先 ...
- Werkzeug教程
http://chaoxz2005.blog.163.com/blog/static/15036542012863405266/ http://www.dajo.com.cn/a/boke/pytho ...
- Flask学习记录之使用Werkzeug散列密码
数据库中直接存放明文密码是很危险的,Werkzeug库中的security能够方便的实现散列密码的计算 security库中 generate_password_hash(password,metho ...
- Werkzeug源码阅读笔记(四)
今天主要讲一下werkzeug中的routing模块.这个模块是werkzeug中的重点模块,Flask中的路由相关的操作使用的都是这个模块 routing模块的用法 在讲解模块的源码之前,先讲讲这个 ...
- Werkzeug源码阅读笔记(三)
这次主要讲下werkzeug中的Local. 源码在werkzeug/local.py Thread Local 在Python中,状态是保存在对象中.Thread Local是一种特殊的对象,它是对 ...
- werkzeug源码阅读笔记(二) 下
wsgi.py----第二部分 pop_path_info()函数 先测试一下这个函数的作用: >>> from werkzeug.wsgi import pop_path_info ...
- werkzeug中服务器处理请求的实现
当成功建立好服务器后,接下来就是等待请求并处理请求通过路由分配给相应的视图函数了,以下是函数调用过程 -> self._handle_request_noblock() /usr/lib/pyt ...
- werkzeug中reloader的实现
在用flask开发时,如果把use_reloader设为True(debug设为True也能实现),那当你修改了app代码或调用环境发生改变时,服务器会自动重启,如下 * Detected chang ...
- Flask之WSGI:Werkzeug
WSGI 一个Web应用的本质就是: 浏览器发送一个HTTP请求: 服务器收到请求,生成一个HTML文档: 服务器把HTML文档作为HTTP响应的Body发送给浏览器: 浏览器收到HTTP响应,从HT ...
- 关于flask自带web应用服务器Werkzeug 使用requests请求时出现的错误。
先说明一下当时的情况,下午遇到一个需求需要先从jd那边拿到图片然后上传到本地的cdn服务器来获取对应的ident 和地址. 于是就需要首先拿到京东的图片url,然后按照图片url去请求图片到内存然后再 ...
随机推荐
- Socket编程:UDP和TCP概论及案例
网络编程的三要素: 1.IP地址 2.端口 3.协议 什么是Socket? Socket就是通信链路的端点称"套接词". 基于TCP协议的Socket网络通信: 用来实现双向安全 ...
- Docker 架构原理及简单使用
提示:文中有些内容为大神的博客内容,就不统一标注那里引用,只是再最下面标注参考连接谢谢 一.简介 1.了解docker的前生LXC LXC为Linux Container的简写.可以提供轻量级的虚拟化 ...
- 用 bat 文件实现 excel 周报复制
又要写周报???? 写周报就算了每次都要改这一大堆的日期,什么鬼嘛,最骚的我还总是有的忘记改.... 作为一个正儿八经的程序员,固定每周某天干重复的一件事,哦~~ 这是机器人 程序应 ...
- Python基础总结之初步认识---class类的继承(终)。第十六天开始(新手可相互督促)
最近生病了,python更新要结束了,但是这才是真正的开始.因为后面要更新的是UnitTest单元测试框架,以及后续的Requests库.在后续的笔记会补充一些python的其他细节笔记.我想是这样的 ...
- 解决微信二次分享失败--后面被加上from=singlemessage&isappinstalled=0的解决方案
首次分享成功,点开后再次分享或第三次分享就失败了 1.检查你分享的链接,看是否多了两个参数,微信分享会根据分享的不同,为原始链接拼接: 朋友圈 from=timeline&isappins ...
- C# 基于NPOI+Office COM组件 实现20行代码在线预览文档(word,excel,pdf,txt,png)
由于项目需要,需要一个在线预览office的功能,小编一开始使用的是微软提供的方法,简单快捷,但是不符合小编开发需求, 就另外用了:将文件转换成html文件然后预览html文件的方法.对微软提供的方法 ...
- Jvm内存泄漏
内存泄漏和内存溢出的关系 内存泄露:指程序中动态分配内存给一些临时对象,但是对象不会被GC所回收,它始终占用内存.即被分配的对象可达但已无用. 内存溢出:指程序运行过程中无法申请到足够的内存而导致的一 ...
- 什么是CWS、WBS、OBS
今天公司进行CMMI资质审核,审核人提到了WBS,以前对这些名词没有太过于注意,后经过审核人的审核对这个名词有了一个大致的了解,并结合项目经验和网上的一些资料,编此文档.不为别人,主要怕自己忘记了. ...
- Java 8 为什么会引入lambda 表达式?
Java 8 为什么会引入lambda ? 在Java8出现之前,如果你想传递一段代码到另一个方法里是很不方便的.你几乎不可能将代码块到处传递,因为Java是一个面向对象的语言,因此你要构建一个属于某 ...
- python的魔术方法大全
在Python中,所有以“__”双下划线包起来的方法,都统称为“Magic Method”(魔术方法),例如类的初始化方法 __init__ ,Python中所有的魔术方法均在官方文档中有相应描述,这 ...