首先,介绍什么是werkzeug。 werkzeug是Web框架的基础WSGI工具包。 这里稍微说明一下,werkzeug既不是web服务器,也不是web框架,而是工具包。 据官方介绍,它是一个WSGI工具包,可以用作web框架的基础库。 因为封装了Request、Response等很多web框架的东西。
例如,我最常用的Flask框架是基于Werkzeug开发的。 所以,解析Werkzeug的基础。 因为我想知道Flask的实现逻辑和基础控制。 虽然本文没有涉及Flask,但我们使用Werkzeug创建了一个简单的web APP演示,并以该web APP演示为例分析了请求处理和响应生成过程。
从简单的例子开始吧。 让我们先看一下werkzeug的使用方法,然后探索werkzeug的实现原理。
要安装werkzeug,我希望读者在virtualenv环境中跟随我的脚步。 如果你还不知道什么是virtualenv,请在我的博客上搜索virtualenv,先修好再继续。 因为由于数据库的冲突等问题,很有可能看不到本文介绍的内容。
确定,接下来开始安装werkzeug。
1
pipinstallWerkzeug
如果这个命令继续的话,几秒钟后就可以使用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/结实的包/env python
# encoding: utf-8
输入
fromwerkzeug.servingimportrun _ simple
fromwerkzeug.wrappersimportrequest,Response
fromwerkzeug.wsgiimportshareddatamiddleware
类短(object ) :
defdispatch_request(self,request ) :
返回响应(' hellowerkzeug!' ) )
efwsgi_app(self,environ,start_response ) :
request=request (环境)
response=self.dispatch _ request (request )
返回响应(environ,start_response ) )。
def__call__(self,environ,start_response ) :
returnself.wsgi_app(Environ,start_response ) )。
defcreate_app(with_static=true ) :
APP=shortly ()
ifwith_static:
app.wsgi _ app=shared data middleware (app.wsgi _ app,{
'/static ' : OS.path.join (OS.path.dirname (_ _ file _ )、' static ' ) ) ) ) ) ) )。
() )
返回应用程序
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. run_simple 解析okay,我们这个系列博客的目的就是解析 werkzeug 源码,所以拿到 werkzeug 源码肯定是我们必须要做的。所以第一步我们就需要从 github 上将 werkzeug clone 下来:
1
git clone https://github.com/mitsuhiko/werkzeug.git
然后,我们就找 run_simple 的代码咯
1
vim werkzeug/serving.py
goto line 559
我们可以看到这个函数的定义,秉着关注重点的原则,我们就忽略条件判断,以一条最简单地路线来看代码,那么这里就假设:
1
2
3
use_debugger = False
static_files = False
use_reloader = False
OK, 那到这里其实 run_simple 调用的就是 inner 了,那么就来看看 inner 的代码:
1
2
3
4
5
6
7
8
9
10
11
646: try:
647: fd = int(os.environ['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
6
650: srv = make_server(hostname, port, application, threaded,
651: processes, request_handler,
652: passthrough_errors, ssl_context,
653: fd=fd)
656: srv.serve_forever()
好,你应该和我一样有兴致得想知道这个 make_server 里面是什么内容了,我也很期待,那就跟上去看看。
make_server 的代码我就不贴了,还是最简原则,忽略各种条件,那么这里就假设:
1
2
threaded = False
processes = 1
那么代码也很简单了,就剩下:
1
2
546: return BaseWSGIServer(host, port, app, request_handler,
547: passthrough_errors, ssl_context, fd=fd)
很好,好不容易跟踪到这,终于上关键了,那就是这个 BaseWSGIServer 了,我们就来看看这个类实现了什么功能。
先看这个类的定义:
1
443: class BaseWSGIServer(HTTPServer, object):
这个类是继承自 HTTPServer 的,那么我们就有点底了,这差不多到头了,已经和 Python 的 API 碰上了。好,既然是继承自 HTTPServer,那么就把他当做 HTTPServer,然后继续看 run_simple 的代码,我们一路跟踪下来,我们发现了 656 行有一个 srv.serve_forever(),那么这不就是 HTTPServer 的用法吗? server.serve_forever() 。
okay,到这那么事情已经暂告一段落了,虽然很多事情都还没搞清楚,例如请求是怎么被封装的,响应又在哪里被处理了,例如URL路由之类的怎么操作的。但是,我们已经对 Werkzeug 有一个大概的印象了,知道他底层还是 HTTPServer 实现的,没有太多特殊的自定义协议。在下一章我们会逐步得进行进行更深层次的解密。欢迎继续关注。