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,
1pip 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)
31    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.
run_simple 解析
okay,我们这个系列博客的⽬的就是解析 werkzeug 源码,所以拿到 werkzeug 源码肯定是我们必须要做的。所以第⼀步我们就需要从github 上将 werkzeug clone 下来:
1git clone github/mitsuhiko/werkzeug.git
然后,我们就 run_simple 的代码咯
1vim werkzeug/serving.py
goto line 559
我们可以看到这个函数的定义,秉着关注重点的原则,我们就忽略条件判断,以⼀条最简单地路线来看代码,那么这⾥就假设:
1 2 3use_debugger = False static_files = False use_reloader = False
OK, 那到这⾥其实 run_simple 调⽤的就是 inner 了,那么就来看看 inner 的代码:
1 2 3 4 5 6 7 8 9 10 11646: try:
647:  fd = viron['WERKZEUG_SERVER_FD'])
648: except (LookupError, ValueError):
649:  fd = None
650: srv = make_server(hostname, port, application, threaded, 651:                  processes, request_handler,
652:                  passthrough_errors, ssl_context,
653:                  fd=fd)
654: if fd is None:
655:  log_startup(srv.socket)
656: srv.serve_forever()
忽略 fd,那么剩下⼀点点了:
1 2 3 4 5 6650: srv = make_server(hostname, port, application, threaded, 651:                    processes, request_handler,
flask下载652:                  passthrough_errors, ssl_context,
653:                  fd=fd)
656: srv.serve_forever()
好,你应该和我⼀样有兴致得想知道这个 make_server ⾥⾯是什么内容了,我也很期待,那就跟上去看看。make_server 的代码我就不贴了,还是最简原则,忽略各种条件,那么这⾥就假设:
1 2threaded = False processes = 1
那么代码也很简单了,就剩下:
1 2546: return BaseWSGIServer(host, port, app, request_handler, 547:                      passthrough_er
rors, ssl_context, fd=fd)
很好,好不容易跟踪到这,终于上关键了,那就是这个 BaseWSGIServer 了,我们就来看看这个类实现了什么功能。
先看这个类的定义:
1443: class BaseWSGIServer(HTTPServer, object):
这个类是继承⾃ HTTPServer 的,那么我们就有点底了,这差不多到头了,已经和 Python 的 API 碰上了。好,既然是继承⾃HTTPServer,那么就把他当做 HTTPServer,然后继续看 run_simple 的代码,我们⼀路跟踪下来,我们发现了 656 ⾏有⼀
个 srv.serve_forever(),那么这不就是 HTTPServer 的⽤法吗? server.serve_forever() 。
okay,到这那么事情已经暂告⼀段落了,虽然很多事情都还没搞清楚,例如请求是怎么被封装的,响应⼜在哪⾥被处理了,例如URL路由之类的怎么操作的。但是,我们已经对 Werkzeug 有⼀个⼤概的印象了,知道他低层还是 HTTPServer 实现的,没有太多特殊的⾃定义协议。在下⼀章我们会逐步得进⾏进⾏更深层次的解密。欢迎继续关注。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。