Pylons 请求生命周期
本文对 Pylons 中对一个请求的处理过程中内部调用的大致轮廓进行了简单的勾勒.
首先通过命令 paster create --template=pylons yourproject 创建一个项目. 然后 ==>
" yourproject_dir::command "
# 读取配置文件并启动服务器和应用程序 paster serve development.ini ==>
" yourproject_dir::development.ini "
#PasteScript 的命令会通过配置文件中指定的 {{{egg
的 entry_points 找到相应的对象[server:main] # 指定 paster serve 使用的 web 服务器 use = egg:Paste#http [app:main] use = egg:yourproject ==> }}}
" yourproject_dir/setup.py "
" yourproject.__init__.py "
1 from yourproject.config.middleware import make_app ==>
" yourproject.config.middleware.py "
1 def make_app(...):
2 ...
3 # 核心 app
4 app = pylons.wsgiapp.PylonsApp(config) ==>
5 app = ConfigMiddleware(app, ... )
6 # YOUR MIDDLEWARE
7 # 将 HTTPExceptions 转换成 HTTP responses
8 app = httpexceptions.make_middleware(app, ... )
9 app = ErrorHandler(app, ... )
10 # 处理静态文件
11 static_app = StaticURLParser(...)
12 # 处理 webhelpers 中使用到的 javascript 文件
13 javascripts_app = StaticJavascripts()
14 # 该中间件的作用是: 对列表中的 app 一个一个尝试, 如果 app 产生 404 错误则继续试下一个
15 app = Cascade([static_app, javascripts_app, app])
16 app = ErrorDocuments(app, ... )
17 #
18 app = RegistryManager(app)
19 return app
" pylons.wsgiapp.py "
" pylons.wsgiapp.py "
1 class PylonsBaseWSGIApp(object):
2 def __init__(self ... )
3 ...
4 def __call__(self, environ, start_response):
5 #正常情况下大致执行流程:
6 self.setup_app_env(...)
7 req = pylons.request._current_obj()
8 # 通过 url dispatcher (routes) 找到相应 controller
9 controller = self.resolve(environ, start_response)
10 # 执行该 controller
11 response = self.dispatch(controller, environ, start_response)
12 status, response_headers, content = response.wsgi_response()
13 start_response(status, response_headers)
14 return content
15 ...
16
17 def dispatch(self, controller, environ, start_response):
18 # 如果是 class, 则实例化之
19 if not hasattr(controller, '__class__') or \
20 getattr(controller, '__class__') == type:
21 controller = controller()
22
23 # 把它当个 wsgi application 调用之
24 return controller(environ, start_response) ==>
" pylons.controllers.py "
1 class Controller(object):
2 ...
3 def _dispatch_call(self):
4 """将请求分发到具体函数"""
5 action = self._req.environ['pylons.routes_dict'].get('action')
6 action_method = action.replace('-', '_')
7 func = getattr(self, action_method, None)
8 if isinstance(func, types.MethodType):
9 response = self._inspect_call(func)
10 else:
11 if asbool(CONFIG['global_conf'].get('debug')):
12 raise NotImplementedError('Action %s is not implemented' % action)
13 else:
14 response = pylons.Response(code=404)
15 return response
16
17 class WSGIController(Controller):
18 ...
19 def __call__(self, environ, start_response):
20 self.start_response = start_response
21 match = environ['pylons.routes_dict']
22 self._req = pylons.request._current_obj()
23
24 # 不调用私有方法
25 if match.get('action').startswith('_'):
26 return pylons.Response(code=404)
27
28 if hasattr(self, '__before__'):
29 self._inspect_call(self.__before__)
30 # 此方法请看上面的 Controller 类
31 response = self._dispatch_call()
32 if hasattr(self, '__after__'):
33 self._inspect_call(self.__after__)
34
35 if hasattr(response, 'wsgi_response'):
36 status, response_headers, content = response.wsgi_response()
37 start_response(status, response_headers)
38
39 # 如果是在测试, 将 response 放到测试环境中去
40 if environ.get('paste.testing'):
41 environ['paste.testing_variables']['response'] = response
42 response = content
43
44 return response
45
46 class RPCController(object):
47 ...