CherryPy是一个Python的web框架,它为Python开发人员提供了一个到HTTP协议的友好接口。它也被称为web应用程序库。
CherryPy利用Python作为动态语言的优势,将HTTP协议建模并绑定到API中。它是Python最古老的web框架之一,提供了干净的界面和可靠的平台。
History of CherryPy
雷米·德隆在2002年6月底发布了第一个版本的樱桃。这是一个成功的Python web库的起点。Remi是一名法国黑客,他相信Python是web应用程序开发的最佳替代方案之一。
Remi开发的项目吸引了许多对这种方法感兴趣的开发人员。该方法具有以下特点:;
CherryPy接近模型-视图-控制器模式。
CherryPy类必须由CherryPy引擎处理和编译,才能生成一个独立的Python模块,嵌入完整的应用程序和它自己的内置web服务器。
CherryPy可以将URL及其查询字符串映射到Python方法调用中,例如−
http://somehost.net/echo?message=hello would map to echo(message='hello')
在CherryPy项目开发的两年中,它得到了社区的支持,Remi发布了几个改进版本。
2004年6月,开始讨论该项目的未来以及是否应继续采用同一结构。经过几位项目常客的头脑风暴和讨论,最终产生了对象发布引擎和过滤器的概念,很快成为CherryPy2的核心部分。后来,在2004年10月,发布了CherryPy2Alpha的第一个版本,作为这些核心思想概念的证明。CherryPy2.0是一个真正的成功;然而,人们认识到它的设计仍然可以改进,需要重构。
在基于反馈的讨论之后,CherryPy的API被进一步修改以提高其优雅性,从而在2005年10月发布了CherryPy 2.1.0。经过多次修改,该团队于2006年4月发布了Cherrypy2.2.0。
Strengths of CherryPy
樱桃红的以下特征被认为是它的强项;
Simplicity
在CherryPy中开发项目是一项简单的任务,只需按照Python的约定和缩进开发几行代码。
CherryPy也非常模块化。使用正确的逻辑概念对主要组件进行了良好的管理,父类可以扩展到子类。
Power
CherryPy充分利用了Python的所有功能。它还提供工具和插件,它们是开发世界级应用程序所需的强大扩展点。
Open-source
CherryPy是一个开源Python Web框架(在开源BSD许可下获得许可),这意味着这个框架可以零成本商业化使用。
Community Help
它有一个专门的社区,提供各种类型的问题和答案的全面支持。社区试图从初级到高级为开发人员提供全面的帮助。
Deployment
有一些经济有效的方法来部署应用程序。CherryPy包含自己的生产就绪HTTP服务器来托管您的应用程序。CherryPy也可以部署在任何符合WSGI的网关上。
CherryPy - Environment Setup
CherryPy与大多数开源项目一样,都有一些包,可以通过以下几种方式下载和安装它们;
- Using a Tarball
- Using easy_install
- Using Subversion
Requirements
CherryPy框架安装的基本要求包括&;
- Python with version 2.4 or above
- CherryPy 3.0
安装Python模块被认为是一个简单的过程。安装包括使用以下命令。
python setup.py build python setup.py install
Python的包存储在以下默认目录中−
- On UNIX or Linux,
/usr/local/lib/python2.4/site-packages or /usr/lib/python2.4/site-packages
- On Microsoft Windows,
C:\Python or C:\Python2x
- On Mac OS,
Python:Lib:site-package
Installation using Tarball
Tarball是文件或目录的压缩存档。CherryPy框架为其每个版本(alpha、beta和stable)提供了一个Tarball。
它包含库的完整源代码。这个名称来自UNIX和其他操作系统中使用的实用程序。
下面是使用tar ball−安装CherryPy的步骤;
步骤1−根据用户要求从
步骤2−搜索下载Tarball的目录并解压缩。对于Linux操作系统,键入以下命令−
tar zxvf cherrypy-x.y.z.tgz
对于Microsoft Windows,用户可以使用7-Zip或Winzip等实用程序通过图形界面解压缩归档文件。
步骤3−移动到新创建的目录并使用以下命令构建CherryPy−
python setup.py build
对于全局安装,应使用以下命令−
python setup.py install
Installation using easy_install
Python企业应用工具包(PEAK)提供了一个名为Easy Install的Python模块。这有助于Python包的部署。这个模块简化了下载、构建和部署Python应用程序和产品的过程。
在安装CherryPy之前,需要在系统中安装Easy Install。
步骤1−从http://peak.telecommunity.com/dist/ez-setup.py>http://peak.telecommunity.com/dist/ez-setup.py下载ez-setup.py模块,并使用计算机上的管理权限运行它:python ez-setup.py。
步骤2−以下命令用于安装Easy install。
easy_install product_name
步骤3−easy_install将搜索Python包索引(PyPI)以找到给定的产品。PyPI是所有Python产品的信息集中存储库。
使用以下命令部署最新可用版本的CherryPy−
easy_install cherrypy
步骤4−easy_install随后将下载CherryPy,构建并将其全局安装到Python环境中。
Installation using Subversion
在以下情况下,建议使用Subversion安装CherryPy;
功能存在或错误已修复,并且仅在正在开发的代码中可用。
当开发人员在CherryPy上工作时。
当用户需要版本控制存储库中主分支的分支时。
用于修复以前版本的错误。
subversion的基本原则是注册存储库并跟踪每个版本,其中包括一系列的更改。
按照以下步骤理解使用Subversion−安装CherryPy;
步骤1−要使用项目的最新版本,必须签出Subversion存储库中的trunk文件夹。
步骤2−从shell输入以下命令−
svn co http://svn.cherrypy.org/trunk cherrypy
步骤3−现在,创建一个CherryPy目录并将完整的源代码下载到其中。
Testing the Installation
需要验证应用程序是否已正确安装在系统中,就像我们对Java等应用程序所做的那样。
您可以选择前一章中提到的三种方法中的任何一种来在您的环境中安装和部署CherryPy。CherryPy必须能够从Python shell导入如下所示&负;
import cherrypy cherrypy.__version__ '3.0.0'
如果CherryPy没有全局安装到本地系统的Python环境中,那么您需要设置PYTHONPATH环境变量,否则它将以以下方式显示错误−
import cherrypy Traceback (most recent call last): File "<stdin>", line 1, in ? ImportError: No module named cherrypy
CherryPy - Vocabulary
为了理解CherryPy的工作原理,需要定义一些重要的关键字。关键字和定义如下&-减;
S.No | Keyword & Definition |
---|---|
1. | Web服务器 它是一个处理HTTP协议的接口。它的目标是将HTTP请求转换为应用服务器,以便它们获得响应。 |
2. | 应用程序 它是一个收集信息的软件。 |
3. | 应用服务器 它是包含一个或多个应用程序的组件 |
4. | Web应用服务器 它是web服务器和应用服务器的结合。 |
Example
下面的示例显示CherryPy−
import cherrypy class demoExample: def index(self): return "Hello World!!!" index.exposed = True cherrypy.quickstart(demoExample())
现在让我们了解代码是如何工作的;
名为CherryPy的包总是导入到指定的类中,以确保正常运行。
在上面的例子中,名为index的函数返回参数“Hello World!!!”.
最后一行启动web服务器并调用指定的类(这里是demoExample)并返回默认函数索引中提到的值。
示例代码返回以下输出−
Built-in Http Server & Internal Engine
CherryPy自带了自己的web(HTTP)服务器。这就是为什么CherryPy是自包含的,允许用户在获得库的几分钟内运行CherryPy应用程序。
web服务器充当应用程序的网关,通过它,所有请求和响应都保持在跟踪状态。
要启动web服务器,用户必须进行以下调用−
cherryPy.server.quickstart()
CherryPy的内部引擎负责以下活动&负;
- Creation and management of request and response objects.
- Controlling and managing the CherryPy process.
CherryPy – Configuration
这个框架有自己的配置系统,允许您参数化HTTP服务器。配置的设置可以存储在语法接近INI格式的文本文件中,也可以存储为完整的Python字典。
要配置CherryPy服务器实例,开发人员需要使用设置的全局部分。
global_conf = { 'global': { 'server.socket_host': 'localhost', 'server.socket_port': 8080, }, } application_conf = { '/style.css': { 'tools.staticfile.on': True, 'tools.staticfile.filename': os.path.join(_curdir, 'style.css'), } } This could be represented in a file like this: [global] server.socket_host = "localhost" server.socket_port = 8080 [/style.css] tools.staticfile.on = True tools.staticfile.filename = "/full/path/to.style.css"
HTTP Compliance
CherryPy的发展很缓慢,但它包括在HTTP/1.0的支持下编译HTTP规范,随后在HTTP/1.1的支持下传输。
CherryPy据说是有条件地符合HTTP/1.1的,因为它实现了规范的所有必须和必需级别,但不是所有应该级别。因此,CherryPy支持HTTP/1.1的以下特性−
如果客户机声称支持HTTP/1.1,则必须在使用指定协议版本发出的任何请求中发送头字段。如果不这样做,CherryPy将立即停止处理请求。
CherryPy生成一个日期头字段,用于所有配置。
CherryPy可以在客户机的支持下处理响应状态代码(100)。
CherryPy的内置HTTP服务器通过使用Connection:Keep-Alive头支持HTTP/1.1中默认的持久连接。
CherryPy处理正确的分块请求和响应。
CherryPy以两种不同的方式支持请求−If Modified Since和If Unmodified Since报头,并相应地根据请求发送响应。
CherryPy允许任何HTTP方法。
CherryPy处理客户端和服务器设置之间的HTTP版本组合。
Multithreaded Application Server
CherryPy是基于多线程概念设计的。每次开发人员获取或设置CherryPy名称空间的值时,都是在多线程环境中完成的。
cherrypy.request和cherrypy.response都是线程数据容器,这意味着您的应用程序通过知道在运行时通过它们代理哪个请求来独立调用它们。
使用线程模式的应用服务器不被高度重视,因为线程的使用被视为增加了由于同步需求而出现问题的可能性。
其他的选择包括&减;
Multi-process Pattern
每个请求都由其自己的Python进程处理。在这里,服务器的性能和稳定性可以被认为是更好的。
Asynchronous Pattern
在这里,接受新连接并将数据发送回客户端是从请求进程异步完成的。这项技术以其效率而闻名。
URL Dispatching
CherryPy社区希望更加灵活,希望为调度员提供其他解决方案。CherryPy 3提供了其他内置的调度器,并提供了一种编写和使用自己的调度器的简单方法。
- Applications used to develop HTTP methods. (GET, POST, PUT, etc.)
- The one which defines the routes in the URL – Routes Dispatcher
HTTP Method Dispatcher
在某些应用程序中,uri独立于要由服务器在资源上执行的操作。
例如,http://xyz.com/album/delete/10
URI包含客户端希望执行的操作。
默认情况下,CherryPy dispatcher将按以下方式映射−
album.delete(12)
上面提到的调度器是正确的,但是可以通过以下方式使其独立&负;
http://xyz.com/album/10
用户可能想知道服务器是如何发送精确的页面的。此信息由HTTP请求本身携带。当有从客户端到服务器的请求时,CherryPy看起来是最合适的处理程序,该处理程序是URI目标资源的表示。
DELETE /album/12 HTTP/1.1
Routes Dispatcher
以下是分派中所需方法的参数列表−
name参数是要连接的路由的唯一名称。
路由是匹配uri的模式。
控制器是包含页处理程序的实例。
使用路由分派器连接与uri匹配的模式并关联特定的页处理程序。
Example
让我们举一个例子来了解它是如何工作的;
import random import string import cherrypy class StringMaker(object): @cherrypy.expose def index(self): return "Hello! How are you?" @cherrypy.expose def generate(self, length=9): return ''.join(random.sample(string.hexdigits, int(length))) if __name__ == '__main__': cherrypy.quickstart(StringMaker ())
按照下面给出的步骤获得上述代码的输出;
第1步−将上述文件另存为tutRoutes.py。
步骤2−访问以下URL−
http://localhost:8080/generate?length=10
步骤3−您将收到以下输出−
CherryPy - ToolBox
在CherryPy中,内置工具提供一个调用CherryPy库的接口。CherryPy中定义的工具可以通过以下方式实现&负;
- From the configuration settings
- As a Python decorator or via the special _cp_config attribute of a page handler
- As a Python callable that can be applied from within any function
Basic Authentication Tool
此工具的目的是为应用程序中设计的应用程序提供基本身份验证。
Arguments
此工具使用以下参数−
Name | Default | Description |
---|---|---|
realm | N/A | String defining the realm value. |
users | N/A | Dictionary of the form − username:password or a Python callable function returning such a dictionary. |
encrypt | None | Python callable used to encrypt the password returned by the client and compare it with the encrypted password provided in the users dictionary. |
Example
让我们举一个例子来了解它是如何工作的;
import sha import cherrypy class Root: @cherrypy.expose def index(self): return """ <html> <head></head> <body> <a href = "admin">Admin </a> </body> </html> """ class Admin: @cherrypy.expose def index(self): return "This is a private area" if __name__ == '__main__': def get_users(): # 'test': 'test' return {'test': 'b110ba61c4c0873d3101e10871082fbbfd3'} def encrypt_pwd(token): return sha.new(token).hexdigest() conf = {'/admin': {'tools.basic_auth.on': True, tools.basic_auth.realm': 'Website name', 'tools.basic_auth.users': get_users, 'tools.basic_auth.encrypt': encrypt_pwd}} root = Root() root.admin = Admin() cherrypy.quickstart(root, '/', config=conf)
get users函数返回一个硬编码字典,但也从数据库或其他任何地方获取值。类admin包括这个函数,它使用CherryPy的一个内置认证工具。身份验证对密码和用户Id进行加密。
基本的身份验证工具并不真正安全,因为密码可以被入侵者编码和解码。
Caching Tool
这个工具的目的是为CherryPy生成的内容提供内存缓存。
Arguments
此工具使用以下参数−
Name | Default | Description |
---|---|---|
invalid_methods | ("POST", "PUT", "DELETE") | Tuples of strings of HTTP methods not to be cached. These methods will also invalidate (delete) any cached copy of the resource. |
cache_Class | MemoryCache | Class object to be used for caching |
Decoding Tool
此工具的目的是解码传入的请求参数。
Arguments
此工具使用以下参数−
Name | Default | Description |
---|---|---|
encoding | None | It looks for the content-type header |
Default_encoding | "UTF-8" | Default encoding to be used when none is provided or found. |
Example
让我们举一个例子来了解它是如何工作的;
import cherrypy from cherrypy import tools class Root: @cherrypy.expose def index(self): return """ <html> <head></head> <body> <form action = "hello.html" method = "post"> <input type = "text" name = "name" value = "" /> <input type = ”submit” name = "submit"/> </form> </body> </html> """ @cherrypy.expose @tools.decode(encoding='ISO-88510-1') def hello(self, name): return "Hello %s" % (name, ) if __name__ == '__main__': cherrypy.quickstart(Root(), '/')
上面的代码从用户那里获取一个字符串,并将用户重定向到“hello.html”页面,在该页面上,它将以给定的名称显示为“hello”。
上述代码的输出如下所示&负;
hello.html
CherryPy - A Working Application
Full stack applications provide a facility to create a new application via some command or execution of the file.
Consider the Python applications like web2py framework; the entire project/application is created in terms of MVC framework. Likewise, CherryPy allows the user to set up and configure the layout of the code as per their requirements.
In this chapter, we will learn in detail how to create CherryPy application and execute it.
File System
The file system of the application is shown in the following screenshot −
Here is a brief description of the various files that we have in the file system −
config.py − Every application needs a configuration file and a way to load it. This functionality can be defined in config.py.
controllers.py−MVC是用户遵循的流行设计模式。controllers.py是实现所有对象的位置,这些对象将安装在cherrypy.tree上。
models.py−此文件直接与数据库交互,用于某些服务或存储持久数据。
server.py−此文件与可正常使用负载平衡代理的生产就绪web服务器交互。
Static−它包含所有CSS和图像文件。
视图包括给定应用程序的所有模板文件。
Example
让我们详细了解创建CherryPy应用程序的步骤。
步骤1−创建一个应包含该应用程序的应用程序。
步骤2−在目录中,创建与项目对应的python包。创建gedit目录,并在其中包含\u init\py文件。
步骤3−在包中,包含controllers.py文件,其中包含以下内容−
#!/usr/bin/env python import cherrypy class Root(object): def __init__(self, data): self.data = data @cherrypy.expose def index(self): return 'Hi! Welcome to your application' def main(filename): data = {} # will be replaced with proper functionality later # configuration file cherrypy.config.update({ 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', 'tools.decode.on': True, 'tools.trailing_slash.on': True, 'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)), }) cherrypy.quickstart(Root(data), '/', { '/media': { 'tools.staticdir.on': True, 'tools.staticdir.dir': 'static' } }) if __name__ == '__main__': main(sys.argv[1])
步骤4−考虑用户通过表单输入值的应用程序。让我们在应用程序中包含两个表单-index.html和submit.html。
步骤5−在上面的控制器代码中,我们有一个index(),这是一个默认函数,如果调用了特定的控制器,则首先加载。
步骤6−可以按以下方式更改index()方法的实现−
@cherrypy.expose def index(self): tmpl = loader.load('index.html') return tmpl.generate(title='Sample').render('html', doctype='html')
步骤7−这将在启动给定应用程序时加载index.html并将其指向给定的输出流。index.html文件如下所示−
index.html
<!DOCTYPE html > <html> <head> <title>Sample</title> </head> <body class = "index"> <div id = "header"> <h1>Sample Application</h1> </div> <p>Welcome!</p> <div id = "footer"> <hr> </div> </body> </html>
步骤8−如果要创建一个接受名称和标题等值的窗体,则必须将方法添加到controller.py中的根类。
@cherrypy.expose def submit(self, cancel = False, **value): if cherrypy.request.method == 'POST': if cancel: raise cherrypy.HTTPRedirect('/') # to cancel the action link = Link(**value) self.data[link.id] = link raise cherrypy.HTTPRedirect('/') tmp = loader.load('submit.html') streamValue = tmp.generate() return streamValue.render('html', doctype='html')
步骤9−submit.html中包含的代码如下−
<!DOCTYPE html> <head> <title>Input the new link</title> </head> <body class = "submit"> <div id = " header"> <h1>Submit new link</h1> </div> <form action = "" method = "post"> <table summary = ""> <tr> <th><label for = " username">Your name:</label></th> <td><input type = " text" id = " username" name = " username" /></td> </tr> <tr> <th><label for = " url">Link URL:</label></th> <td><input type = " text" id=" url" name= " url" /></td> </tr> <tr> <th><label for = " title">Title:</label></th> <td><input type = " text" name = " title" /></td> </tr> <tr> <td></td> <td> <input type = " submit" value = " Submit" /> <input type = " submit" name = " cancel" value = "Cancel" /> </td> </tr> </table> </form> <div id = "footer"> </div> </body> </html>
步骤10−您将收到以下输出−
这里,方法名被定义为“POST”。交叉验证文件中指定的方法总是很重要的。如果该方法包含“POST”方法,则应在数据库中的相应字段中重新检查这些值。
如果方法包含“GET”方法,则要保存的值将在URL中可见。
CherryPy - Web Services
web服务是一组基于web的组件,有助于在应用程序或系统之间交换数据,这些应用程序或系统还包括开放协议和标准。它可以在网上发布、使用和找到。
Web服务有多种类型,如RWS(restfulweb服务)、WSDL、SOAP等等。
REST — Representational State Transfer
一种远程访问协议,它将状态从客户端传输到服务器,服务器可用来操作状态,而不是调用远程过程。
不定义任何特定的编码或结构以及返回有用错误消息的方式。
使用HTTP“动词”执行状态传输操作。
资源是使用URL唯一标识的。
它不是一个API,而是一个API传输层。
REST维护网络上资源的命名,并提供对这些资源执行操作的统一机制。每个资源由至少一个标识符标识。如果REST基础设施是以HTTP为基础实现的,那么这些标识符被称为统一资源标识符(Uniform Resource identifiers,uri)。
以下是URI集的两个公共子集−
Subset | Full form | Example |
---|---|---|
URL | Uniform Resource Locator | http://www.gmail.com/ |
URN | Uniform Resource Name | urn:isbn:0-201-71088-9 urn:uuid:13e8cf26-2a25-11db-8693-000ae4ea7d46 |
在理解CherryPy体系结构的实现之前,让我们先关注一下CherryPy的体系结构。
CherryPy包括以下三个部分&负;
cherrypy.engine−它控制流程启动/拆卸和事件处理。
cherrypy.server
tools是与处理HTTP请求正交的实用程序工具箱。
REST Interface through CherryPy
RESTful web服务通过以下帮助实现CherryPy体系结构的每个部分:;
- Authentication
- Authorization
- Structure
- Encapsulation
- Error Handling
Authentication
身份验证有助于验证与我们交互的用户。CherryPy包括处理每个身份验证方法的工具。
def authenticate(): if not hasattr(cherrypy.request, 'user') or cherrypy.request.user is None: # < Do stuff to look up your users > cherrypy.request.authorized = False # This only authenticates. Authz must be handled separately. cherrypy.request.unauthorized_reasons = [] cherrypy.request.authorization_queries = [] cherrypy.tools.authenticate = \ cherrypy.Tool('before_handler', authenticate, priority=10)
上面的函数authenticate()将帮助验证客户机或用户的存在。内置工具有助于以系统的方式完成该过程。
Authorization
授权有助于通过URI维护进程的健全性。该过程也有助于通过用户令牌导程变形对象。
def authorize_all(): cherrypy.request.authorized = 'authorize_all' cherrypy.tools.authorize_all = cherrypy.Tool('before_handler', authorize_all, priority=11) def is_authorized(): if not cherrypy.request.authorized: raise cherrypy.HTTPError("403 Forbidden", ','.join(cherrypy.request.unauthorized_reasons)) cherrypy.tools.is_authorized = cherrypy.Tool('before_handler', is_authorized, priority = 49) cherrypy.config.update({ 'tools.is_authorized.on': True, 'tools.authorize_all.on': True })
如前一个例子所述,授权的内置工具有助于以系统的方式处理例程。
Structure
维护API的结构有助于减少映射应用程序URI的工作量。始终有必要保持API的可发现性和清洁性。CherryPy框架API的基本结构应该有以下几个方面:;
- Accounts and User
- Autoresponder
- Contact
- File
- Folder
- List and field
- Message and Batch
Encapsulation
封装有助于创建轻量级、可读性和可供各种客户端访问的API。项目列表以及创建、检索、更新和删除都需要封装API。
Error Handling
如果API不能按照特定的本能执行,这个过程会管理错误(如果有的话)。例如,400表示错误请求,403表示未授权请求。
Example
以下是数据库、验证或应用程序错误的示例。
import cherrypy import json def error_page_default(status, message, traceback, version): ret = { 'status': status, 'version': version, 'message': [message], 'traceback': traceback } return json.dumps(ret) class Root: _cp_config = {'error_page.default': error_page_default} @cherrypy.expose def index(self): raise cherrypy.HTTPError(500, "Internal Sever Error") cherrypy.quickstart(Root())
上面的代码将产生以下输出&负;
由于内置的访问工具,通过CherryPy可以轻松管理API(应用程序编程接口)。
HTTP Methods
对资源进行操作的HTTP方法列表如下−
S.No | HTTP Method & Operation |
---|---|
1. | 头部 检索资源元数据。 |
2. | 我不知道。我不知道。 检索资源元数据和内容。 |
3. | 岗位 请求服务器使用请求正文中包含的数据创建新资源。 |
4. | 投入 请求服务器用请求正文中包含的资源替换现有资源。 |
5. | 删除 请求服务器删除由该URI标识的资源。 |
6. | 选项 请求服务器返回有关全局或特定于资源的功能的详细信息。 |
Atom Publishing Protocol (APP)
APP是Atom社区的一个应用程序级协议,它位于HTTP之上,允许发布和编辑web资源。应用服务器和客户端之间的消息单元基于Atom XML文档格式。
Atom发布协议使用HTTP及其机制和Atom XML文档格式作为消息单元,定义了应用程序服务和用户代理之间的一组操作。
APP首先定义一个服务文档,该文档向用户代理提供APP服务提供的不同集合的URI。
Example
让我们举一个例子来演示APP是如何工作的;
<?xml version = "1.0" encoding = "UTF-8"?> <service xmlns = "http://purl.org/atom/app#" xmlns:atom = "http://www.w3.org/2005/Atom"> <workspace> <collection href = "http://host/service/atompub/album/"> <atom:title> Albums</atom:title> <categories fixed = "yes"> <atom:category term = "friends" /> </categories> </collection> <collection href = "http://host/service/atompub/film/"> <atom:title>Films</atom:title> <accept>image/png,image/jpeg</accept> </collection> </workspace> </service>
APP指定如何使用下表中描述的HTTP方法对集合的成员或集合本身执行基本CRUD操作;
Operation | HTTP Method | Status Code | Content |
---|---|---|---|
Retrieve | GET | 200 | An Atom entry representing the resource |
Create | POST | 201 | The URI of the newly created resource via the Location and Content-Location headers |
Update | PUT | 200 | An Atom entry representing the resource |
Delete | DELETE | 200 | None |
CherryPy - Presentation Layer
表示层确保通过它的通信以预期的接收者为目标。CherryPy通过各种模板引擎维护表示层的工作。
模板引擎在业务逻辑的帮助下获取页面的输入,然后将其处理到只针对预期受众的最终页面。
Kid — The Template Engine
Kid是一个简单的模板引擎,它包括待处理模板的名称(这是必需的)和呈现模板时要传递的数据的输入。
在第一次创建模板时,Kid创建了一个Python模块,该模块可以用作模板的缓存版本。
函数返回模板类的一个实例,该实例可用于呈现输出内容。
template类提供了以下一组命令−
S.No | Command & Description |
---|---|
1. | 序列化 它将输出内容作为字符串返回。 |
2. | 产生 它将输出内容作为迭代器返回。 |
3. | 写 它将输出内容转储到文件对象中。 |
这些命令使用的参数如下−
S.No | Command & Description |
---|---|
1. | 编码 它通知如何对输出内容进行编码 |
2. | 碎片 它是一个布尔值,告诉XML prolog或Doctype |
3. | 输出 这种类型的序列化用于呈现内容 |
Example
让我们举一个例子来了解孩子是如何工作的;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html xmlns:py = "http://purl.org/kid/ns#"> <head> <title>${title}</title> <link rel = "stylesheet" href = "style.css" /> </head> <body> <p>${message}</p> </body> </html> The next step after saving the file is to process the template via the Kid engine. import kid params = {'title': 'Hello world!!', 'message': 'CherryPy.'} t = kid.Template('helloworld.kid', **params) print t.serialize(output='html')
Kid's Attributes
以下是Kid的属性;
XML-Based Templating Language
它是一种基于XML的语言。Kid模板必须是具有正确命名约定的格式良好的XML文档。
Kid在XML元素中实现属性,以更新到达该元素所遵循的操作的底层引擎。为了避免与XML文档中的其他现有属性重叠,Kid引入了自己的名称空间。
<p py:if = "...">...</p>
Variable Substitution
Kid提供了一个变量替换方案和一个简单的方法-${variable name}。
变量可以用于元素的属性中,也可以用作元素的文本内容。Kid将在每次执行时计算变量。
如果用户需要将文本字符串输出为${something},则可以使用变量替换将美元符号加倍来对其进行转义。
Conditional Statement
为了在模板中切换不同的情况,使用了以下语法−
<tag py:if = "expression">...</tag>
这里,tag是元素的名称,例如DIV或SPAN。
表达式是一个Python表达式。如果作为布尔值,它的计算结果为True,则元素将包含在输出内容中,否则它将不是输出内容的一部分。
Looping Mechanism
为了循环Kid中的元素,使用了以下语法−
<tag py:for = "expression">...</tag>
这里,tag是元素的名称。表达式是一个Python表达式,例如,[…]中的值。
Example
下面的代码演示循环机制是如何工作的;
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>${title}</title> <link rel = "stylesheet" href = "style.css" /> </head> <body> <table> <caption>A few songs</caption> <tr> <th>Artist</th> <th>Album</th> <th>Title</th> </tr> <tr py:for = "info in infos"> <td>${info['artist']}</td> <td>${info['album']}</td> <td>${info['song']}</td> </tr> </table> </body> </html> import kid params = discography.retrieve_songs() t = kid.Template('songs.kid', **params) print t.serialize(output='html')
The 输出 for the above code with the looping mechanism is as follows −
CherryPy - Use Of Ajax
直到2005年,所有web应用程序遵循的模式都是管理每页一个HTTP请求。将一个页面导航到另一个页面需要加载整个页面。这将在更大程度上降低性能。
因此,用于将AJAX、XML和JSON嵌入其中的富客户端应用程序出现了增长。
AJAX
异步JavaScript和XML(AJAX)是一种创建快速动态web页面的技术。AJAX允许通过在后台与服务器交换少量数据来异步更新web页面。这意味着可以更新网页的部分内容,而不必重新加载整个网页。
Google Maps、Gmail、YouTube和Facebook是AJAX应用程序的几个例子。
Ajax基于使用JavaScript发送HTTP请求的思想;更具体地说,Ajax依赖XMLHttpRequest对象及其API来执行这些操作。
JSON
JSON是一种携带序列化JavaScript对象的方式,这样JavaScript应用程序就可以对它们进行求值并将它们转换为JavaScript对象,这些对象可以在以后进行操作。
例如,当用户向服务器请求用JSON格式格式化的唱片集对象时,服务器将返回以下输出−
{'description': 'This is a simple demo album for you to test', 'author': ‘xyz’}
现在,数据是一个JavaScript关联数组,可以通过−访问描述字段;
data ['description'];
Applying AJAX to the Application
考虑一下这个应用程序,它包含一个名为“media”的文件夹,其中包含index.html和Jquery插件,以及一个带有AJAX实现的文件。让我们考虑文件名为“ajax_app.py”
ajax_app.py
import cherrypy import webbrowser import os import simplejson import sys MEDIA_DIR = os.path.join(os.path.abspath("."), u"media") class AjaxApp(object): @cherrypy.expose def index(self): return open(os.path.join(MEDIA_DIR, u'index.html')) @cherrypy.expose def submit(self, name): cherrypy.response.headers['Content-Type'] = 'application/json' return simplejson.dumps(dict(title="Hello, %s" % name)) config = {'/media': {'tools.staticdir.on': True, 'tools.staticdir.dir': MEDIA_DIR,} } def open_page(): webbrowser.open("http://127.0.0.1:8080/") cherrypy.engine.subscribe('start', open_page) cherrypy.tree.mount(AjaxApp(), '/', config=config) cherrypy.engine.start()
类“AjaxApp”重定向到“index.html”的网页,该网页包含在媒体文件夹中。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" lang = "en" xml:lang = "en"> <head> <title>AJAX with jQuery and cherrypy</title> <meta http-equiv = " Content-Type" content = " text/html; charset=utf-8" /> <script type = " text/javascript" src = " /media/jquery-1.4.2.min.js"></script> <script type = " text/javascript"> $(function() { // When the testform is submitted... $("#formtest").submit(function() { // post the form values via AJAX... $.post('/submit', {name: $("#name").val()}, function(data) { // and set the title with the result $("#title").html(data['title']) ; }); return false ; }); }); </script> </head> <body> <h1 id = "title">What's your name?</h1> <form id = " formtest" action = " #" method = " post"> <p> <label for = " name">Name:</label> <input type = " text" id = "name" /> <br /> <input type = " submit" value = " Set" /> </p> </form> </body> </html>
AJAX的函数包含在<script>标记中。
Output
上面的代码将产生以下输出&负;
一旦用户提交了值,AJAX功能就会实现,屏幕就会重定向到如下所示的表单−
CherryPy - Demo Application
在本章中,我们将重点讨论如何在CherryPy框架中创建应用程序。
考虑一下CherryPy演示应用程序的Photoblog应用程序。Photoblog应用程序是一个普通的blog,但是主要的文本是照片而不是文本。Photoblog应用程序的主要特点是开发人员可以更加专注于设计和实现。
Basic Structure – Design of Entities
实体设计应用程序的基本结构。以下是Photoblog应用程序的实体;
- Film
- Photo
- Album
下面是实体关系的基本类图−
Design Structure
如前一章所述,项目的设计结构如下截图所示;
考虑给定的应用程序,它有Photoblog应用程序的子目录。子目录是Photo、Album和Film,其中包括controllers.py、models.py和server.py。
从功能上讲,Photoblog应用程序将提供api,通过传统的CRUD接口(Create、Retrieve、Update和Delete)来操作这些实体。
Connection to the Database
存储模块包括一组操作;与数据库的连接是操作之一。
由于它是一个完整的应用程序,与数据库的连接对于API是必需的,并且要维护创建、检索、更新和删除的功能。
import dejavu arena = dejavu.Arena() from model import Album, Film, Photo def connect(): conf = {'Connect': "host=localhost dbname=Photoblog user=test password=test"} arena.add_store("main", "postgres", conf) arena.register_all(globals())
上面代码中的竞技场将是底层存储管理器和业务逻辑层之间的接口。
connect函数将存储管理器添加到PostgreSQL RDBMS的arena对象中。
一旦获得连接,我们就可以根据业务需求创建表单并完成应用程序的工作。
在创建任何应用程序之前,最重要的是实体映射和设计应用程序的结构。
CherryPy - Testing
测试是一个过程,在这个过程中,应用程序从不同的角度进行,以便-;
- Find the list of issues
- Find differences between the expected and actual result, output, states, etc.
- Understand the implementation phase.
- Find the application useful for realistic purposes.
测试的目标不是让开发人员犯错,而是提供工具并提高质量,以便在给定的时间估计应用程序的运行状况。
测试需要提前计划。这就要求定义测试的目的,理解测试用例的范围,列出业务需求,并意识到项目不同阶段所涉及的风险。
测试定义为一系列要在系统或应用程序上验证的方面。以下是常见测试方法的列表;
单元测试通常由开发人员自己执行。其目的是检查代码单元是否按预期工作。
可用性测试−开发人员通常会忘记他们正在为不了解系统的最终用户编写应用程序。可用性测试验证了产品的优缺点。
功能/验收测试−当可用性测试检查应用程序或系统是否可用时,功能测试确保每个指定的功能都已实现。
进行负载和性能测试−是为了了解系统是否能够适应要进行的负载和性能测试。这可能导致硬件更改、优化SQL查询等。
回归测试−它验证产品的连续发布不会破坏以前的任何功能。
可靠性和弹性测试&负;可靠性测试有助于在一个或多个组件出现故障时验证系统应用程序。
Unit Testing
Photoblog应用程序经常使用单元测试来检查以下各项;
- New functionalities work correctly and as expected.
- Existing functionalities are not broken by new code release.
- Defects are fixed and remain fixed.
Python附带了一个标准的unittest模块,提供了不同的单元测试方法。
Unittest
unit test源于JUnit,一个由Kent Beck和Erich Gamma开发的Java单元测试包。单元测试只返回定义的数据。可以定义模拟对象。这些对象允许对我们设计的接口进行测试,而不必依赖于整个应用程序。它们还提供了在隔离模式下运行包含其他测试的测试的方法。
让我们用以下方式定义一个虚拟类−
import unittest class DummyTest(unittest.TestCase): def test_01_forward(self): dummy = Dummy(right_boundary=3) self.assertEqual(dummy.forward(), 1) self.assertEqual(dummy.forward(), 2) self.assertEqual(dummy.forward(), 3) self.assertRaises(ValueError, dummy.forward) def test_02_backward(self): dummy = Dummy(left_boundary=-3, allow_negative=True) self.assertEqual(dummy.backward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.backward(), -3) self.assertRaises(ValueError, dummy.backward) def test_03_boundaries(self): dummy = Dummy(right_boundary=3, left_boundary=-3,allow_negative=True) self.assertEqual(dummy.backward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.forward(), -1) self.assertEqual(dummy.backward(), -2) self.assertEqual(dummy.backward(), -3)
代码的解释如下所示;
应导入unit test模块,以便为给定类提供单元测试功能。
类应该通过子类unittest创建。
上面代码中的每个方法都以单词测试开始。所有这些方法都由unittest处理程序调用。
测试用例调用assert/fail方法来管理异常。
将此视为运行测试用例的一个示例−
if __name__ == '__main__': unittest.main()
运行测试用例的结果(输出)如下所示;
---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
Functional Testing
一旦应用程序功能按照需求开始成形,一组功能测试就可以验证应用程序关于规范的正确性。然而,测试应该自动化,以获得更好的性能,这将需要使用第三方产品,如硒。
CherryPy提供了类似helper类的内置函数,以简化函数测试的编写。
Load Testing
根据您正在编写的应用程序和您对卷的期望,您可能需要运行负载和性能测试,以便检测应用程序中阻止其达到某个性能级别的潜在瓶颈。
本节将不详细说明如何进行性能或负载测试,因为它不在FunkLoad包中。
FunkLoad最基本的例子如下所示;
from funkload.FunkLoadTestCase import FunkLoadTestCase class LoadHomePage(FunkLoadTestCase): def test_homepage(self): server_url = self.conf_get('main', 'url') nb_time = self.conf_getInt('test_homepage', 'nb_time') home_page = "%s/" % server_url for i in range(nb_time): self.logd('Try %i' % i) self.get(home_page, description='Get gome page') if __name__ in ('main', '__main__'): import unittest unittest.main()
下面是对上述代码的详细解释;
测试用例必须继承自FunkLoad test case类,这样FunkLoad就可以完成跟踪测试期间发生的事情的内部工作。
类名很重要,因为FunkLoad将根据类名查找文件。
设计的测试用例可以直接访问配置文件。只需对服务器调用Get()和post()方法即可获得响应。
CherryPy - Deployment Of Application
本章将重点介绍通过内置CherryPy HTTP服务器启用的基于CherryPy的应用SSL。
Configuration
web应用程序中需要不同级别的配置设置;
Web服务器−链接到HTTP服务器的设置
引擎−与引擎宿主相关的设置
应用程序 − Application which is used by the user
Deployment
CherryPy应用程序的部署被认为是一种非常简单的方法,其中所有必需的包都可以从Python系统路径获得。在共享的web托管环境中,web服务器将驻留在前端,允许主机提供程序执行筛选操作。前端服务器可以是Apache或lighttpd。
本节将介绍一些在Apache和lighttpd web服务器后面运行CherryPy应用程序的解决方案。
cherrypy def setup_app(): class Root: @cherrypy.expose def index(self): # Return the hostname used by CherryPy and the remote # caller IP address return "Hello there %s from IP: %s " % (cherrypy.request.base, cherrypy.request.remote.ip) cherrypy.config.update({'server.socket_port': 9091, 'environment': 'production', 'log.screen': False, 'show_tracebacks': False}) cherrypy.tree.mount(Root()) if __name__ == '__main__': setup_app() cherrypy.server.quickstart() cherrypy.engine.start()
SSL
基于CherryPy的应用程序可以支持SSL(安全套接字层)。要启用SSL支持,必须满足以下要求&负;
- Have the PyOpenSSL package installed in user’s environment
- Have an SSL certificate and private key on the server
Creating a Certificate and a Private Key
我们来处理证书和私钥的要求;
- First the user needs a private key −
openssl genrsa -out server.key 2048
- This key is not protected by a password and therefore has a weak protection.
- The following command will be issued −
openssl genrsa -des3 -out server.key 2048
程序将需要密码短语。如果您的OpenSSL版本允许您提供空字符串,请执行此操作。否则,请输入默认密码短语,然后按以下方式将其从生成的密钥中移除−
openssl rsa -in server.key -out server.key
- Creation of the certificate is as follows −
openssl req -new -key server.key -out server.csr
此过程将要求您输入一些详细信息。为此,必须发出以下命令&负;
openssl x509 -req -days 60 -in server.csr -signkey server.key -out server.crt
新签署的证书有效期为60天。
下面的代码显示了它的实现−
import cherrypy import os, os.path localDir = os.path.abspath(os.path.dirname(__file__)) CA = os.path.join(localDir, 'server.crt') KEY = os.path.join(localDir, 'server.key') def setup_server(): class Root: @cherrypy.expose def index(self): return "Hello there!" cherrypy.tree.mount(Root()) if __name__ == '__main__': setup_server() cherrypy.config.update({'server.socket_port': 8443, 'environment': 'production', 'log.screen': True, 'server.ssl_certificate': CA, 'server.ssl_private_key': KEY}) cherrypy.server.quickstart() cherrypy.engine.start()
下一步是启动服务器;如果成功,您将在屏幕上看到以下消息−