## page was renamed from PyLons/call-cycle <> = 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}}} " {{{#!python entry_points=""" [paste.app_factory] main=yourproject:make_app ==> ... """ }}} " {{{yourproject.__init__.py}}} " {{{#!python from yourproject.config.middleware import make_app ==> }}} " {{{yourproject.config.middleware.py}}} " {{{#!python def make_app(...): ... # 核心 app app = PyLons.wsgiapp.PyLonsApp(config) ==> app = ConfigMiddleware(app, ... ) # YOUR MIDDLEWARE # 将 HTTPExceptions 转换成 HTTP responses app = httpexceptions.make_middleware(app, ... ) app = ErrorHandler(app, ... ) # 处理静态文件 static_app = StaticURLParser(...) # 处理 webhelpers 中使用到的 javascript 文件 javascripts_app = StaticJavascripts() # 该中间件的作用是: 对列表中的 app 一个一个尝试, 如果 app 产生 404 错误则继续试下一个 app = Cascade([static_app, javascripts_app, app]) app = ErrorDocuments(app, ... ) # app = RegistryManager(app) return app }}} " {{{PyLons.wsgiapp.py}}} " {{{#!python class PyLonsApp(object): def __init__(self, ...): self.app = PyLonsBaseWSGIApp(... ) ==> def __call__(self, environ, start_response): ... return self.app(environ, start_response) }}} " {{{PyLons.wsgiapp.py}}} " {{{#!python class PyLonsBaseWSGIApp(object): def __init__(self ... ) ... def __call__(self, environ, start_response): #正常情况下大致执行流程: self.setup_app_env(...) req = PyLons.request._current_obj() # 通过 url dispatcher (routes) 找到相应 controller controller = self.resolve(environ, start_response) # 执行该 controller response = self.dispatch(controller, environ, start_response) status, response_headers, content = response.wsgi_response() start_response(status, response_headers) return content ... def dispatch(self, controller, environ, start_response): # 如果是 class, 则实例化之 if not hasattr(controller, '__class__') or \ getattr(controller, '__class__') == type: controller = controller() # 把它当个 wsgi application 调用之 return controller(environ, start_response) ==> }}} " {{{PyLons.controllers.py}}} " {{{#!python class Controller(object): ... def _dispatch_call(self): """将请求分发到具体函数""" action = self._req.environ['PyLons.routes_dict'].get('action') action_method = action.replace('-', '_') func = getattr(self, action_method, None) if isinstance(func, types.MethodType): response = self._inspect_call(func) else: if asbool(CONFIG['global_conf'].get('debug')): raise NotImplementedError('Action %s is not implemented' % action) else: response = PyLons.Response(code=404) return response class WSGIController(Controller): ... def __call__(self, environ, start_response): self.start_response = start_response match = environ['PyLons.routes_dict'] self._req = PyLons.request._current_obj() # 不调用私有方法 if match.get('action').startswith('_'): return PyLons.Response(code=404) if hasattr(self, '__before__'): self._inspect_call(self.__before__) # 此方法请看上面的 Controller 类 response = self._dispatch_call() if hasattr(self, '__after__'): self._inspect_call(self.__after__) if hasattr(response, 'wsgi_response'): # 估计返回的是 paste.wsgiwrappers.WSGIResponse status, response_headers, content = response.wsgi_response() start_response(status, response_headers) # 如果是在测试, 将 response 放到测试环境中去 if environ.get('paste.testing'): environ['paste.testing_variables']['response'] = response response = content # 看来是个 WSGI应用程序 的 Response return response class RPCController(object): ... }}} = 结论 = 从中我们大致可以看出 PyLons 扩展的潜力: * 首先用户代码中通过命令 {{{paster controller controllername}}} 生成的 {{{Controller}}} 都默认继承自 {{{yourproject.lib.base.BaseController}}} ( 后者继承自 {{{PyLons.controllers.WSGIController}}} ), 那么修改 {{{BaseController}}} 可以影响到所有默认生成的 {{{Controller}}} * Controller 中有两个特殊的方法 {{{__before__}}} 和 {{{__after__}}}, 这个两个方法的行为可以影响到当前 {{{controller}}} 中所有 {{{action}}} * 在 {{{yourproject/config/middleware.py}}} 添加其他 wsgi中间件. * 在 {{{Controller}}} 中直接调用标准的 WSGI 应用程序 并返回其结果 * 而且注意到 {{{PyLonsApp}}} 和 {{{WSGIController}}} 都是 WSGI应用程序, 不过里面通过 {{{environ}}} 依赖到一些其他的东西, 比如 routes, 单独拿出来用的意义似乎不太大 :-( ....