Flask这个人人称赞的微框架就是构建在werkzeug之上,werkzeug给自己的定位就是工具集合。它实现了wsgi server、Requests/Response封装、DEBUG、热重启、路由控制以及其他的一些辅助功能。接下来的几篇文章会从一些大的方面去分析它。本篇如标题:D
WSGI Server
这个初略说一下。和它相关的代码不多。和wsgiref一样它构建在python自带模块SocketServer和BaseHTTPRequestHandler之上。甚至比自带的wsgiref代码要少。它主要增加了SSL和socket.fromfd支持。并且将debug、静态文件分发、热重启组合再了一起
Request、Response封装
这个可能算是重点了。有个库webob就是专门做这个的。占得代码量也很大。可惜我并不想详细写每一个的过程,太麻烦了,了解了大概就好啦。以后会主要分析下datastructures.py这个文件。下面是超简洁的原理代码
| 12
 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
 
 | class Request():def __init__(self, env):
 pass
 
 @classmethod
 def application(cls, f):
 def decorator(env, start_response):
 request = cls(env)
 return f(request)(env, start_response)
 
 return decorator
 
 
 class Response():
 def __init__(self, str):
 self.body = str
 
 def __call__(self, env, start_response):
 start_response('200 OK', [])
 return [self.body]
 
 
 @Request.application
 def app(req):
 return Response(b'Hello')
 
 
 from wsgiref.simple_server import make_server
 
 make_server('', 8000, app).serve_forever()
 
 | 
可以大概了解是这么回事:
- Request它主要封装的是headers,然后嘞,各种属性都用property就好了,剩下的body和其他的也差不多啦。
- Request.application这个装饰器的作用就是将原来的env,start_response参数变成req给我们使用
- Response它就是一个wsgiapp对象
 看下它们2个的继承图
  | 12
 3
 4
 5
 
 | class PlainRequest(StreamOnlyMixin, Request):
 class Response(BaseResponse, ETagResponseMixin, ResponseStreamMixin,
 CommonResponseDescriptorsMixin,
 WWWAuthenticateMixin):
 
 |  
 
热重启实现原理
上简图:

上原理代码:
| 12
 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
 32
 33
 34
 35
 36
 
 | import osimport sys
 import time
 import subprocess
 import threading
 
 
 def main():
 print('Hello')
 
 
 def file_change():
 mtimes = {}
 while 1:
 filename = __file__
 mtime = os.stat(filename).st_mtime
 old_time = mtimes.get(filename)
 if old_time is None:
 mtimes[filename] = mtime
 continue
 elif mtime > old_time:
 print(' * Detected change in {}, reloading'.format(filename))
 os._exit(3)
 time.sleep(1)
 
 
 if os.environ.get('secord_process'):
 threading.Thread(target=main, args=()).start()
 file_change()
 else:
 while 1:
 env = os.environ.copy()
 env['secord_process'] = 'true'
 exit_code = subprocess.call([sys.executable] + sys.argv, env=env)
 if exit_code != 3:
 break
 
 | 
做法就是主线程啥事没做,跑一个死循环,生成子进程(就相当运行自身,区别就是os.environ)。这个进程内使用单独的线程跑需要运行的函数,另外就是检查相关文件是否被改变。改变就执行sys.exit。然后就又被主线程的死循环生成了新的子进程