你可以使用CherryPy编写的最基本的web应用程序,几乎涉及其所有核心概念。
import cherrypy
class Root(object):
@cherrypy.expose
def index(self):
return "Hello World!"
if __name__ == '__namin__':
cherrypy.quickstart(Root(), '/')
在讨论他之前,我们先跳到第九行,他显示了如何使用CherrPy的服务器托管你的应用程序,
并在"/"路径上启用内置的HTTP服务器服务。
现在回到实际的应用程序,虽然CherryPy并没有强制要求,但是大部分时候应用程序将被编写为Python类。
CherryPy将调用这些类的方法来响应客户端请求。需要注意的是,类方法能被CherryPy调用,我们说该方法被暴露。
这正是装饰器cherrypy.expose()在第四行做的。
将上面这段代码保存在名为myapp.py的文件中,并运行他:
$ python myapp.py
然后打开浏览器 http://127.0.0.1:8080
注意
CherryPy是一个专注于一个单一任务的小框架;接受HTTP请求,并找到与请求URL匹配的Python函数或方法。
与其他知名框架不同,CherrPy不提供对数据库访问,HTML模板或任何其他中间件功能的内置支持。
简而言之,CherryPy发现并调用一个被暴露的方法,由开发人员负责提供实现应用程序的逻辑。
警告
前面的例子展示了CherryPy接口的简单性,但是实际上你的应用程序可能还包含了其他几个部分:
静态文件、更复杂的结构、数据库访问等。
CherryPy是一个极小的框架,但不是一个简单的框架,他附带了一些基本的工具来实现您期待的常用功能。
托管一个或多个应用程序:
Web应用程序需要一个可访问的HTTP服务器。CherryPy提供自己的准备好的HTTP服务器。有两种方式来托管
应用程序。都很简单。
单一应用
最直接的方法是使用cherrypy.quickstart()功能。他需要至少一个参数,即应用程序的实例。另外还有两个可选参数。
第一个是应用程序可以访问的基本路径。第二个是一个配置字典或文件用来配置所托管的应用程序。
cherrpy.quickstart(Blog())
cherrpy.quickstart(Blog(), '/blog')
cherrpy.quickstart(Blog(), '/blog', {'/': {'tools.gzip.on': True}})
另外,最后一个例子为应用程序提供了具体的配置。
cherrypy.quickstart()方法对于单个应用程序是好用的,但是缺乏使用服务器托管多个应用程序的能力。
要实现这一点,需要使用cherrypy.tree.mount 功能:
cherrypy.tree.mount(Blog(), '/blog', blog_conf)
cherrypy.tree.mount(Forum(), '/forum', forum_conf)
cherrypy.engine.start()
cherrypy.engine.block()
cherrypy.quickstart() 和 cherrypy.tree.mount 并不是相互排斥的, 例如上面的行可以写成:
cherrypy.tree.mount(Blog(), '/blog', blog_conf)
cherrypy.quickstart(Forum(), '/forum', forum_conf)
在任何应用程序中, 日志记录是一项重要任务。 CherryPy将记录所有传入的请求及错误。
为此, CherryPy管理着两个记录器:
一个记录每个传入请求的访问
一个跟踪错误或其他应用程序级的消息
你的应用程序可以通过调用来利用第二个记录器 cherrypy.log()。
cherrypy.log("你好")
try:
...
except:
cherrypy.log("kaboom!", traceback=True)
log.access_file 对传入请求使用通用日志格式
log.error_file 其他日志
cherrypy.config.update({'log.screen': False,
'log.access_file': '',
'log.error_file': ''})
import logging
import logging.config
import cherrypy
logger = logging.getLogger()
db_logger = logging.getLogger('db')
LOG_CONF = {
'version': 1,
'formatters': {
'void': {
'format': ''
},
'standard': {
'format': '%(asctime)s [%(levelname)s] %(name)s: %(message)s'
},
},
'handlers': {
'default': {
'level':'INFO',
'class':'logging.StreamHandler',
'formatter': 'standard',
'stream': 'ext://sys.stdout'
},
'cherrypy_console': {
'level':'INFO',
'class':'logging.StreamHandler',
'formatter': 'void',
'stream': 'ext://sys.stdout'
},
'cherrypy_access': {
'level':'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'void',
'filename': 'access.log',
'maxBytes': 10485760,
'backupCount': 20,
'encoding': 'utf8'
},
'cherrypy_error': {
'level':'INFO',
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'void',
'filename': 'errors.log',
'maxBytes': 10485760,
'backupCount': 20,
'encoding': 'utf8'
},
},
'loggers': {
'': {
'handlers': ['default'],
'level': 'INFO'
},
'db': {
'handlers': ['default'],
'level': 'INFO' ,
'propagate': False
},
'cherrypy.access': {
'handlers': ['cherrypy_access'],
'level': 'INFO',
'propagate': False
},
'cherrypy.error': {
'handlers': ['cherrypy_console', 'cherrypy_error'],
'level': 'INFO',
'propagate': False
},
}
}
class Root(object):
@cherrypy.expose
def index(self):
logger.info("boom")
db_logger.info("bam")
cherrypy.log("bang")
return "hello world"
if __name__ == '__main__':
cherrypy.config.update({'log.screen': False,
'log.access_file': '',
'log.error_file': ''})
cherrypy.engine.unsubscribe('graceful', cherrypy.log.reopen_files)
logging.config.dictConfig(LOG_CONF)
cherrypy.quickstart(Root())