貌似很多人是零配置控啊,喜欢类似 Flask 一类的零配置路由,不需要在 run.py 中写一个长列表,只需要在接受请求的函数 or 类前面加一个装饰器,正如:
from bottle import route, run
@route('/:name')
def index(name='World'):
return '<strong>Hello %s!</strong>' % name
run(host='localhost', port=8080)
对比 web.py 的集中配置:
import web
urls = ("/.*", "hello")
app = web.application(urls, globals())
class hello:
def GET(self):
return 'Hello, world!'
if __name__ == "__main__":
app.run()
貌似二者没神马区别嘛,只不过把集中的配置分散了。当然对于这个问题也是很多不同看法,有人觉得分散了配置不利统一管理,有人觉得把 url 和请求处理者放在一起有利于模块的无缝装卸。当然最理想的是两种选择都存在。在豆瓣上已经看到有人提出 给 web.py 添加装饰器路由的方式 <http://www.douban.com/group/topic/12998784/> _ 了,我自己也写了个 tornado 版的。
于是,本代码碎片诞生。作为小白,python 实在写的很少,求拍砖求拍砖……
# coding:utf-8
"""
基础模块, 扩展了 Tornado Web 服务器
@author: tonyseek
"""
import tornado.web
import types
class Application(tornado.web.Application):
"""
Tornado 应用实例
"""
def load_module(self, module, **options):
"""
加载 RequestHandler 模块
"""
assert type(module) is types.ModuleType
host_pattern = options.get('host_pattern', '.*$')
# 处理加载 RequestHandler 和路由规则
cls_valid = lambda cls: type(cls) is types.TypeType \
and issubclass(cls, RequestHandler) # 是否有效
url_valid = lambda cls: hasattr(cls, 'url_pattern') \
and cls.url_pattern # 是否拥有 url 规则
mod_attrs = (getattr(module, i) for i in dir(module) \
if not i.startswith('_'))
valid_handlers = ((i.url_pattern, i) for i in mod_attrs \
if cls_valid(i) and url_valid(i))
# 处理完毕载入
self.add_handlers(host_pattern, valid_handlers)
def _get_host_handlers(self, request):
"""
覆盖父类方法, 一次获取所有可匹配的结果. 父类中该方法一次匹配
成功就返回, 忽略后续匹配结果. 现通过使用生成器, 如果一次匹配
的结果不能使用可以继续匹配.
"""
host = request.host.lower().split(':')[0]
# 使用生成器表达式而非列表推导式, 减少性能折扣
handlers = (i for p, h in self.handlers for i in h \
if p.match(host))
if not handlers and "X-Real-Ip" not in request.headers:
handlers = [i for p, h in self.handlers for i in h \
if p.match(self.default_host)]
return handlers
class RequestHandler(tornado.web.RequestHandler):
url_pattern = None
def route(url_pattern):
"""
路由装饰器, 只能装饰 RequestHandler 子类
"""
def handler_wapper(cls):
assert(issubclass(cls, RequestHandler))
cls.url_pattern = url_pattern
return cls
return handler_wapper
下面是一个 RequestHandler 集合,也就是“可装卸”的那货:
@base.route('/')
class Main(base.RequestHandler):
def get(self):
self.write("Hello World")
@base.route('/(.*)')
class Person(base.RequestHandler):
def get(self, name):
self.write(name)
下面 load_handler_module 就是装载模块的方法:
import base
import main.handlers
application = base.Application()
application.load_module(main.handlers)
if __name__ == "__main__":
application.listen(8080)
tornado.ioloop.IOLoop.instance().start()