PECAN & WSGI
一、PECAN
1、简介
pecan是基于python实现的一个轻量化web框架,采用对象分发方式来进行URL路由,其本身不支持session、database等功能,专注于HTTP本身。Pecan也会支持一些扩展属性来建立基于HTTP的应用,包括:
基于对象分发的简单路由
全面支持REST风格控制器
可扩展安全框架
可扩展模板语言支持
可扩展JSON支持
基于Python的简单配置
2、框架
以watcher中api组块为例,其代码结构如下图1:
以此代码结构介绍pecan各模块:
(1)controllers:http路由的核心逻辑,包括一个RootController作为URL路由的根目录
(2)middleware:鉴权相关
(3)acl.py:鉴权相关
(4)app.py:包含get_pecan_config()方法来加载配置和setup_app()方法来创建应用
(5)app.wsgi:None
(6)config.py:pecan配置参数,定义访问入口等信息
(7)hooks.py:钩子类
3、代码示例
(1)controller
class RootController(rest.RestController) v1 = v1_root.V1Controller() @wsme_pecan.wsexpose(Root) def get(sef): return Root.convert()
RootController类继承了pecan.rest.RestController类,在其中定义属性v1,当使用/v1来访问是,即使用该v1对象进行路由,此即对象路由分发。
在get()方法头部使用wsme_pecan.wsexpose注释,将方法暴露出去,才能够外部访问。
(2)app.py
def get_pecan_config(): filename = api_config.__file__.replace('.pyc', '.py') # get the absolute path of the pecan config.py return pecan.configuration.conf_from_file(filename) def setup_app(config=None): # the main function, start listening if not config: config = get_pecan_config() app_conf = dict(config.app) app = pecan.make_app( app_conf.pop('root'), logging=getattr(config, 'logging', {}), **app_conf) return app class VersionSelectorApplication(object): def __init__(self): pc = get_pecan_config() self.v1 = setup_app(config=pc) def __call__(self, environ, start_response): return self.v1(environ, start_response)
(3)config.py
server = { 'port': '9323', 'host': '127.0.0.1' } app = { 'root': 'rtcloud.api.controllers.root.RootController', 'modules': ['rtcloud.api'], 'hooks': [ hooks.ContextHook(), hooks.NoExceptionTracebackHook(), ], 'static_root': '%(confdir)s/public', 'enable_acl': True, 'acl_public_routes': [ '/', ], } # WSME Configurations # See https://wsme.readthedocs.org/en/latest/integrate.html#configuration wsme = { 'debug': cfg.CONF.get("debug") if "debug" in cfg.CONF else False, } PECAN_CONFIG = { "server": server, "app": app, "wsme": wsme, }
(4)hooks.py
class NoExceptionTracebackHook(hooks.PecanHook): """Workaround rpc.common: deserialize_remote_exception. deserialize_remote_exception builds rpc exception traceback into error message which is then sent to the client. Such behavior is a security concern so this hook is aimed to cut-off traceback from the error message. """ # NOTE(max_lobur): 'after' hook used instead of 'on_error' because # 'on_error' never fired for wsme+pecan pair. wsme @wsexpose decorator # catches and handles all the errors, so 'on_error' dedicated for unhandled # exceptions never fired. def after(self, state): # Omit empty body. Some errors may not have body at this level yet. if not state.response.body: return # Do nothing if there is no error. # Status codes in the range 200 (OK) to 399 (400 = BAD_REQUEST) are not # an error. if (http_client.OK <= state.response.status_int < http_client.BAD_REQUEST): return json_body = state.response.json # Do not remove traceback when traceback config is set if cfg.CONF.debug: return faultstring = json_body.get('faultstring') traceback_marker = 'Traceback (most recent call last):' if faultstring and traceback_marker in faultstring: # Cut-off traceback. faultstring = faultstring.split(traceback_marker, 1)[0] # Remove trailing newlines and spaces if any. json_body['faultstring'] = faultstring.rstrip() # Replace the whole json. Cannot change original one because it's # generated on the fly. state.response.json = json_body
pecan.hooks提供了有on_route()、before()、after()和on_error()四种方法。
二、WSGI
1、简介
WSGI(Web Server Gateway Interface),即Web服务器网关接口,是为Python定义的Web服务器和Web应用或框架之间简单而通用的接口。引用一下解释来自知乎网友翻译PEP3333
“
WSGI 接口有服务端和应用端两部分,服务端也可以叫网关端,应用端也叫框架端。服务端调用一个由应用端提供的可调用对象。如何提供这个对象,由服务端决定。例如某些服务器或者网关需要应用的部署者写一段脚本,以创建服务器或者网关的实例,并且为这个实例提供一个应用实例。另一些服务器或者网关则可能使用配置文件或其他方法以指定应用实例应该从哪里导入或获取。
”
接口定义非常简单,以“Hello, web!”为例如下:
def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return [b'<h1>Hello, web!</h1>']
函数必须由WSGI服务器来调用。
2、代码示例
class WSGIService(service.ServiceBase): """Provides ability to launch rtcloud API from wsgi app.""" def __init__(self, service_name, use_ssl=False): """Initialize, but do not start the WSGI server. :param service_name: The service name of the WSGI server. :param use_ssl: Wraps the socket in an SSL context if True. """ self.service_name = service_name self.app = app.VersionSelectorApplication() self.workers = (CONF.api.workers or processutils.get_worker_count()) self.server = wsgi.Server(CONF, self.service_name, self.app, host=CONF.api.host, port=CONF.api.port, use_ssl=use_ssl, logger_name=self.service_name)
在上述代码中,通过self.server.start()即可开启一个基于WSGI的服务。
- 点赞
- 收藏
- 关注作者
评论(0)