CherryPy - 快速指南
CherryPy - Introduction
CherryPy是Python的Web框架,为Python开发人员提供了一个友好的HTTP协议接口。 它也被称为Web应用程序库。
CherryPy使用Python作为动态语言的优势来建模并将HTTP协议绑定到API中。 它是Python最古老的Web框架之一,它提供了干净的界面和可靠的平台。
CherryPy的历史
Remi Delon于2002年6月底发布了第一个版本的CherryPy。这是一个成功的Python Web库的起点。 Remi是一名法国黑客,他信任Python,成为Web应用程序开发的最佳替代方案之一。
Remi开发的项目吸引了许多对该方法感兴趣的开发人员。 该方法包括以下功能 -
CherryPy接近模型 - 视图 - 控制器模式。
必须由CherryPy引擎处理和编译CherryPy类,以生成嵌入完整应用程序以及其自己的内置Web服务器的自包含Python模块。
CherryPy可以将URL及其查询字符串映射到Python方法调用中,例如 -
http://somehost.net/echo?message=hello would map to echo(message='hello')
在CherryPy项目的两年开发期间,它得到了社区的支持,Remi发布了几个改进版本。
2004年6月,开始讨论该项目的未来以及是否应继续采用相同的架构。 几个项目常客的头脑风暴和讨论导致了对象发布引擎和过滤器的概念,很快成为CherryPy2.Later的核心部分,2004年10月,CherryPy 2 alpha的第一个版本被发布作为概念证明这些核心思想。 CherryPy 2.0取得了真正的成功; 然而,人们认识到它的设计仍然可以改进,并且需要重构。
在基于反馈的讨论之后,CherryPy的API进一步修改以改善其优雅,导致2005年10月发布CherryPy 2.1.0。经过各种更改后,该团队于2006年4月发布了CherryPy 2.2.0。
CherryPy的优势
CherryPy的以下功能被视为其优势 -
简约(Simplicity)
在CherryPy中开发项目是一项简单的任务,根据Python的约定和缩进开发了几行代码。
CherryPy也非常模块化。 主要组件使用正确的逻辑概念进行良好管理,父类可扩展为子类。
Power
CherryPy充分利用了Python的所有功能。 它还提供工具和插件,这是开发世界级应用程序所需的强大扩展点。
Open-source
CherryPy是一个开源的Python Web框架(在开源BSD许可下获得许可),这意味着该框架可以以零成本在商业上使用。
社区帮助
它有一个专门的社区,提供各种类型的问题和答案的完整支持。 社区试图从初学者级别到高级级别向开发人员提供全面的帮助。
部署(Deployment)
有一些经济有效的方法来部署应用程序。 CherryPy包含自己的生产就绪HTTP服务器来托管您的应用程序。 CherryPy还可以部署在任何符合WSGI的网关上。
CherryPy - Environment Setup
CherryPy包含大多数开源项目的软件包,可以通过以下各种方式下载和安装 -
- 使用Tarball
- 使用easy_install
- 使用Subversion
要求(Requirements)
安装CherryPy框架的基本要求包括 -
- 2.4版或更高版本的Python
- CherryPy 3.0
安装Python模块被认为是一个简单的过程。 安装包括使用以下命令。
python setup.py build
python setup.py install
Python的包存储在以下默认目录中 -
- 在UNIX或Linux上,
/usr/local/lib/python2.4/site-packages
or
/usr/lib/python2.4/site-packages
- 在Microsoft Windows上
C:\Python or C:\Python2x
- 在Mac OS上,
Python:Lib:site-package
使用Tarball安装
Tarball是文件或目录的压缩存档。 CherryPy框架为其每个版本(alpha,beta和stable)提供Tarball。
它包含库的完整源代码。 该名称来自UNIX和其他操作系统中使用的实用程序。
以下是使用tar球安装CherryPy时应遵循的步骤 -
Step 1 - 根据用户要求从http://download.cherrypy.org/下载版本
Step 2 - 搜索已下载Tarball的目录并解压缩。 对于Linux操作系统,请键入以下命令 -
tar zxvf cherrypy-x.y.z.tgz
对于Microsoft Windows,用户可以使用7-Zip或Winzip等实用程序通过图形界面解压缩存档。
Step 3 - 移动到新创建的目录并使用以下命令构建CherryPy -
python setup.py build
对于全局安装,应使用以下命令 -
python setup.py install
使用easy_install进行安装
Python企业应用程序工具包(PEAK)提供了一个名为Easy Install的python模块。 这有助于部署Python包。 该模块简化了下载,构建和部署Python应用程序和产品的过程。
在安装CherryPy之前,需要在系统中安装Easy Install。
Step 1 - 从http://peak.telecommunity.com下载ez_setup.py模块,并使用计算机上的管理权限运行它:python ez_setup.py。
Step 2 - 以下命令用于安装Easy Install。
easy_install product_name
Step 3 - easy_install将搜索Python包索引(PyPI)以查找给定的产品。 PyPI是所有Python产品的集中信息库。
使用以下命令部署最新的CherryPy版本 -
easy_install cherrypy
Step 4 - easy_install将下载CherryPy,构建并将其全局安装到您的Python环境中。
使用Subversion进行安装
在以下情况下,建议使用Subversion安装CherryPy -
存在一个功能或已修复错误,仅在开发中的代码中可用。
当开发人员在CherryPy上工作时。
当用户需要来自版本控制存储库中的主分支的分支时。
用于修复先前版本的错误。
subversioning的基本原则是注册一个存储库并跟踪每个版本,其中包括一系列的更改。
按照以下步骤使用Subversion了解CherryPy的安装 -
Step 1 - 要使用最新版本的项目,有必要检查Subversion存储库中找到的trunk文件夹。
Step 2 - 从shell输入以下命令 -
svn co http://svn.cherrypy.org/trunk cherrypy
Step 3 - 现在,创建一个CherryPy目录并将完整的源代码下载到其中。
测试安装
需要验证应用程序是否已正确安装在系统中,与我们对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 | 关键字和定义 |
---|---|
1. | Web Server 它是处理HTTP协议的接口。 它的目标是将HTTP请求转换为应用程序服务器,以便它们获得响应。 |
2. | Application 它是一个收集信息的软件。 |
3. | Application server 它是包含一个或多个应用程序的组件 |
4. | Web application server 它是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 server充当应用程序的网关,在此帮助下,所有请求和响应都保持跟踪。
要启动Web服务器,用户必须进行以下调用 -
cherryPy.server.quickstart()
internal engine of CherryPy的internal engine of CherryPy负责以下活动 -
- 创建和管理请求和响应对象。
- 控制和管理CherryPy流程。
CherryPy - 配置
该框架带有自己的配置系统,允许您参数化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合规性
CherryPy一直在发展缓慢,但它包括HTTP规范的编译,HTTP/1.0的支持随后在HTTP/1.1的支持下传输。
据说CherryPy在条件上符合HTTP/1.1,因为它实现了所有必需和必需的级别,但并不是规范的所有应该级别。 因此,CherryPy支持HTTP/1.1的以下功能 -
如果客户端声称支持HTTP/1.1,则它必须在使用指定协议版本的任何请求中发送头字段。 如果没有完成,CherryPy将立即停止处理请求。
CherryPy生成一个Date头字段,用于所有配置。
CherryPy可以在客户的支持下处理响应状态代码(100)。
CherryPy的内置HTTP服务器通过使用Connection:Keep-Alive标头支持HTTP/1.1中的默认持久连接。
CherryPy正确处理分块请求和响应。
CherryPy以两种不同的方式支持请求 - If-Modified-Since和If-Unmodified- Since headers并根据请求相应地发送响应。
CherryPy允许任何HTTP方法。
CherryPy处理客户端和服务器设置集之间的HTTP版本组合。
多线程应用程序服务器
CherryPy是基于多线程概念设计的。 每次开发人员在CherryPy命名空间中获取或设置值时,都会在多线程环境中完成。
cherrypy.request和cherrypy.response都是线程数据容器,这意味着您的应用程序通过知道在运行时通过它们代理哪个请求来独立地调用它们。
使用线程模式的应用程序服务器不被高度重视,因为线程的使用被视为增加了由于同步要求而导致问题的可能性。
其他选择包括 -
Multi-process Pattern
每个请求都由自己的Python进程处理。 在这里,可以认为服务器的性能和稳定性更好。
异步模式
在这里,接受新连接并将数据发送回客户端是从请求过程异步完成的。 该技术以其效率而着称。
URL调度
CherryPy社区希望更灵活,并且可以感谢调度员的其他解决方案。 CherryPy 3提供了其他内置调度程序,并提供了一种编写和使用自己的调度程序的简单方法。
- 用于开发HTTP方法的应用程序。 (GET,POST,PUT等)
- 定义URL中路由的路由 - 路由调度程序
HTTP方法调度程序
在某些应用程序中,URI与操作无关,操作由资源上的服务器执行。
例如, http://xyz.com/album/delete/10
URI包含客户端希望执行的操作。
默认情况下,CherryPy调度程序将以下列方式映射 -
album.delete(12)
上面提到的调度员是正确提到的,但可以通过以下方式独立 -
http://xyz.com/album/10
用户可能想知道服务器如何调度确切的页面。 此信息由HTTP请求本身承载。 当有来自客户端到服务器的请求时,CherryPy看起来是最合适的处理程序,处理程序是URI所针对的资源的表示。
DELETE /album/12 HTTP/1.1
路线调度员
以下是调度所需方法的参数列表 -
name参数是要连接的路由的唯一名称。
路由是匹配URI的模式。
控制器是包含页面处理程序的实例。
使用Routes调度程序连接与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 ())
按照下面给出的步骤获取上述代码的输出 -
Step 1 - 将上述文件另存为tutRoutes.py 。
Step 2 - 访问以下网址 -
http://localhost:8080/generate?length=10
Step 3 - 您将收到以下输出 -
CherryPy - ToolBox
在CherryPy中,内置工具提供单个界面来调用CherryPy库。 CherryPy中定义的工具可以通过以下方式实现 -
- 从配置设置
- 作为Python装饰器或通过页面处理程序的特殊_cp_config属性
- 作为Python可调用,可以从任何函数中应用
基本认证工具
此工具的目的是为应用程序中设计的应用程序提供基本身份验证。
参数 (Arguments)
此工具使用以下参数 -
名称 | 默认 | 描述 |
---|---|---|
realm | N/A | 定义领域值的字符串。 |
users | N/A | 表单的字典 - 用户名:密码或返回此类字典的Python可调用函数。 |
encrypt | None | Python callable用于加密客户端返回的密码,并将其与用户词典中提供的加密密码进行比较。 |
例子 (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。
基本身份验证工具并不十分安全,因为密码可以由入侵者编码和解码。
缓存工具
此工具的目的是提供CherryPy生成内容的内存缓存。
参数 (Arguments)
此工具使用以下参数 -
名称 | 默认 | 描述 |
---|---|---|
invalid_methods | ("POST", "PUT", "DELETE") | 不缓存HTTP方法字符串的元组。 这些方法还将使资源的任何缓存副本无效(删除)。 |
cache_Class | MemoryCache | 用于缓存的类对象 |
解码工具
此工具的目的是解码传入的请求参数。
参数 (Arguments)
此工具使用以下参数 -
名称 | 默认 | 描述 |
---|---|---|
encoding | None | 它查找内容类型标头 |
Default_encoding | "UTF-8" | 未提供或未找到时使用的默认编码。 |
例子 (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
完整堆栈应用程序提供了通过某些命令或文件执行来创建新应用程序的工具。
考虑像web2py框架这样的Python应用程序; 整个项目/应用程序是根据MVC框架创建的。 同样,CherryPy允许用户根据需要设置和配置代码的布局。
在本章中,我们将详细了解如何创建CherryPy应用程序并执行它。
文件系统
该应用程序的文件系统显示在以下屏幕截图中 -
以下是我们在文件系统中拥有的各种文件的简要说明 -
config.py - 每个应用程序都需要配置文件和加载它的方法。 可以在config.py中定义此功能。
controllers.py - MVC是用户遵循的流行设计模式。 controllers.py是实现将安装在cherrypy.tree上的所有对象的地方。
models.py - 此文件直接与数据库交互以获取某些服务或存储持久数据。
server.py - 此文件与生产就绪的Web服务器交互,该服务器可与负载平衡代理正常工作。
Static - 它包含所有CSS和图像文件。
Views - 它包含给定应用程序的所有模板文件。
例子 (Example)
让我们详细了解创建CherryPy应用程序的步骤。
Step 1 - 创建应包含应用程序的应用程序。
Step 2 - 在目录中,创建一个与项目对应的python包。 创建gedit目录并在其中包含_init_.py文件。
Step 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])
Step 4 - 考虑用户通过表单输入值的应用程序。 我们在应用程序中包含两个表单 - index.html和submit.html。
Step 5 - 在上面的控制器代码中,我们有index() ,这是一个默认函数,如果调用特定的控制器,则首先加载。
Step 6 - index()方法的实现可以通过以下方式更改 -
@cherrypy.expose
def index(self):
tmpl = loader.load('index.html')
return tmpl.generate(title='Sample').render('html', doctype='html')
Step 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>
Step 8 - 如果要创建一个接受名称和标题等值的表单,则必须在controller.py的Root类中添加一个方法。
@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')
Step 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>
Step 10 - 您将收到以下输出 -
这里,方法名称定义为“POST”。 交叉验证文件中指定的方法始终很重要。 如果方法包含“POST”方法,则应在适当的字段中在数据库中重新检查这些值。
如果方法包含“GET”方法,则要保存的值将在URL中可见。
CherryPy - Web Services
Web服务是一组基于Web的组件,有助于在应用程序或系统之间交换数据,这些数据还包括开放协议和标准。 它可以在网上发布,使用和发现。
Web服务有各种类型,如RWS(RESTfUL Web服务),WSDL,SOAP等等。
REST - 具象国家转移
一种远程访问协议,它将状态从客户端传输到服务器,可用于操作状态而不是调用远程过程。
没有定义任何特定的编码或结构以及返回有用错误消息的方法。
使用HTTP“动词”执行状态转移操作。
使用URL唯一标识资源。
它不是API,而是API传输层。
REST维护网络上资源的命名,并提供统一的机制来对这些资源执行操作。 每个资源由至少一个标识符标识。 如果REST基础结构是以HTTP为基础实现的,则这些标识符称为Uniform Resource Identifiers (URIs) 。
以下是URI集的两个常见子集 -
子集 | 完整形式 | 例 |
---|---|---|
URL | 统一资源定位器 | http://www.gmail.com/ |
URN | 统一资源名称 | urn:isbn:0-201-71088-9 urn:uuid:13e8cf26-2a25-11db-8693-000ae4ea7d46 |
在了解CherryPy架构的实现之前,让我们关注CherryPy的架构。
CherryPy包括以下三个组件 -
cherrypy.engine - 它控制进程启动/拆卸和事件处理。
cherrypy.server - 它配置和控制WSGI或HTTP服务器。
cherrypy.tools - 与处理HTTP请求正交的实用工具箱。
REST接口通过CherryPy
RESTful Web服务在以下帮助下实现CherryPy架构的每个部分 -
- Authentication
- Authorization
- Structure
- Encapsulation
- 错误处理
身份验证 (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的基本结构应该如下 -
- 帐户和用户
- Autoresponder
- Contact
- File
- Folder
- 列表和字段
- Message and Batch
封装 (Encapsulation)
封装有助于创建轻量级,人类可读且可供各种客户端访问的API。 项目列表以及创建,检索,更新和删除需要封装API。
错误处理
如果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方法
对资源进行操作的HTTP方法列表如下 -
S.No | HTTP方法和操作 |
---|---|
1. | HEAD 检索资源元数据。 |
2. | GET 检索资源元数据和内容。 |
3. | POST 请求服务器使用请求正文中包含的数据创建新资源。 |
4. | PUT 请求服务器将现有资源替换为请求正文中包含的资源。 |
5. | DELETE 请求服务器删除该URI标识的资源。 |
6. | OPTIONS 请求服务器全局或特定地向资源返回有关功能的详细信息。 |
Atom Publishing Protocol (APP)
APP已经从Atom社区出现,作为HTTP之上的应用程序级协议,允许发布和编辑Web资源。 APP服务器和客户端之间的消息单元基于Atom XML文档格式。
Atom发布协议使用HTTP及其机制和Atom XML文档格式作为消息单元,定义APP服务和用户代理之间的一组操作。
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操作,如下表所述 -
手术 | HTTP方法 | 状态代码 | 内容 |
---|---|---|---|
Retrieve | GET | 200 | 表示资源的Atom条目 |
Create | POST | 201 | 通过Location和Content-Location标头创建的新资源的URI |
Update | PUT | 200 | 表示资源的Atom条目 |
Delete | DELETE | 200 | None |
CherryPy - Presentation Layer
表示层确保通过它的通信以目标收件人为目标。 CherryPy通过各种模板引擎维护表示层的工作。
模板引擎在业务逻辑的帮助下获取页面的输入,然后将其处理到仅针对目标受众的最终页面。
孩子 - 模板引擎
Kid是一个简单的模板引擎,它包含要处理的模板的名称(这是必需的)以及在呈现模板时要传递的数据的输入。
在第一次创建模板时,Kid创建了一个Python模块,可以作为模板的缓存版本。
kid.Template函数返回模板类的实例,该实例可用于呈现输出内容。
模板类提供以下命令集 -
S.No | 命令和描述 |
---|---|
1. | serialize 它将输出内容作为字符串返回。 |
2. | generate 它将输出内容作为迭代器返回。 |
3. | write 它将输出内容转储到文件对象中。 |
这些命令使用的参数如下 -
S.No | 命令和描述 |
---|---|
1. | encoding 它通知如何编码输出内容 |
2. | fragment 它是一个布尔值,告诉XML prolog或Doctype |
3. | output 这种类型的序列化用于呈现内容 |
例子 (Example)
让我们举一个例子来了解kid工作方式 -
<!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')
孩子的属性
以下是孩子的属性 -
基于XML的模板语言
它是一种基于XML的语言。 Kid模板必须是格式良好的XML文档,并具有适当的命名约定。
Kid在XML元素中实现属性,以更新到达元素时要遵循的操作的底层引擎。 为了避免与XML文档中的其他现有属性重叠,Kid引入了自己的命名空间。
<p py:if = "...">...</p>
可变替代
Kid带有变量替换方案和简单方法 - $ {variable-name}。
变量既可以用在元素的属性中,也可以用作元素的文本内容。 Kid会在每次执行时评估变量。
如果用户需要将文字字符串的输出作为$ {something},则可以通过将美元符号加倍来使用变量替换来转义它。
Conditional 语句
要在模板中切换不同的大小写,请使用以下语法 -
<tag py:if = "expression">...</tag>
这里,tag是元素的名称,例如DIV或SPAN。
表达式是Python表达式。 如果作为布尔值计算为True,则元素将包含在输出内容中,否则它将不是输出内容的一部分。
循环机制
对于在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')
具有循环机制的上述代码的output如下 -
CherryPy - Use Of Ajax
直到2005年,所有Web应用程序遵循的模式是每页管理一个HTTP请求。 将一个页面导航到另一个页面需要加载整个页面。 这会将性能降低到更高的水平。
因此, rich client applications的数量有所增加,这些rich client applications过去常常嵌入AJAX,XML和JSON。
AJAX
异步JavaScript和XML(AJAX)是一种创建快速动态网页的技术。 AJAX允许通过与服务器交换幕后的少量数据来异步更新网页。 这意味着可以更新网页的各个部分,而无需重新加载整个页面。
Google地图,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'];
将AJAX应用于应用程序
考虑一个应用程序,它包含一个名为“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的功能包含在
输出 (Output)
上面的代码将产生以下输出 -
一旦用户提交了值,就会实现AJAX功能,并将屏幕重定向到表单,如下所示 -
CherryPy - Demo Application
在本章中,我们将重点介绍如何在CherryPy框架中创建应用程序。
考虑将Photoblog应用程序用于CherryPy的演示应用程序。 Photoblog应用程序是一个普通的博客,但主要文本将是照片代替文本。 Photoblog应用程序的主要功能是开发人员可以更专注于设计和实现。
基本结构 - 实体设计
实体设计应用程序的基本结构。 以下是Photoblog应用程序的实体 -
- Film
- Photo
- Album
以下是实体关系的基本类图 -
设计结构
如前一章所述,项目的设计结构如下图所示 -
考虑给定的应用程序,它具有Photoblog应用程序的子目录。 子目录是Photo,Album和Film,其中包括controllers.py,models.py和server.py。
从功能上讲,Photoblog应用程序将提供API以通过传统的CRUD界面 - 创建,检索,更新和删除来操纵这些实体。
连接到数据库
存储模块包括一组操作; 与数据库的连接是其中一个操作。
由于它是一个完整的应用程序,因此API必须与数据库建立连接,并保持Create,Retrieve,Update和Delete的功能。
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对象。
一旦获得连接,我们就可以根据业务需求创建表单并完成应用程序的工作。
在创建任何应用程序之前,最重要的是entity mapping和设计应用程序的结构。
CherryPy - Testing
测试是一个过程,在此过程中,应用程序从不同的角度进行,以便 -
- 找到问题列表
- 找出预期结果与实际结果,输出,状态等之间的差异。
- Understand the implementation phase.
- 找到对实际用途有用的应用程序。
测试的目的不是让开发人员犯错,而是提供工具并提高质量,以便在给定时间估计应用程序的运行状况。
测试需要提前计划。 这需要定义测试目的,理解测试用例的范围,制定业务需求列表以及了解项目不同阶段所涉及的风险。
测试被定义为要在系统或应用程序上验证的一系列方面。 以下列出了common test approaches -
Unit testing - 这通常由开发人员自己执行。 这旨在检查代码单元是否按预期工作。
Usability testing - 开发人员通常会忘记他们正在为不了解系统的最终用户编写应用程序。 可用性测试验证了产品的优缺点。
Functional/Acceptance testing - 可用性测试检查应用程序或系统是否可用,功能测试确保实现每个指定的功能。
Load and performance testing - 执行此操作是为了了解系统是否可以根据要进行的负载和性能测试进行调整。 这可能导致硬件更改,优化SQL查询等。
Regression testing - 它验证产品的连续版本不会破坏任何先前的功能。
Reliability and resilience testing - 可靠性测试有助于通过一个或多个组件的细分来验证系统应用程序。
单元测试 (Unit Testing)
Photoblog应用程序不断使用单元测试来检查以下内容 -
- 新功能正常运行并符合预期。
- 新代码版本不会破坏现有功能。
- 缺陷是固定的并保持固定。
Python带有标准的unittest模块,提供不同的单元测试方法。
Unittest
unittest植根于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)
代码的解释如下 -
应导入unittest模块,以便为给定的类提供单元测试功能。
应该通过继承unittest来创建一个类。
上面代码中的每个方法都以单词test开头。 所有这些方法都由unittest处理程序调用。
测试用例调用assert/fail方法来管理异常。
将此视为运行测试用例的示例 -
if __name__ == '__main__':
unittest.main()
运行测试用例的结果(输出)如下 -
----------------------------------------------------------------------
Ran 3 tests in 0.000s
OK
功能测试 (Functional Testing)
一旦应用程序功能按照要求开始成形,一组功能测试可以验证应用程序关于规范的正确性。 但是,测试应该是自动化的,以获得更好的性能,这需要使用Selenium等第三方产品。
CherryPy提供了类似内置函数的辅助类,以简化功能测试的编写。
负载测试
根据您编写的应用程序和您对卷的期望,您可能需要运行负载和性能测试,以便检测应用程序中阻止其达到某个性能级别的潜在瓶颈。
本节不会详细说明如何进行性能或负载测试,因为它不在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()
以下是上述代码的详细说明 -
测试用例必须从FunkLoadTestCase类继承,以便FunkLoad可以执行内部工作来跟踪测试期间发生的事情。
类名很重要,因为FunkLoad将根据类名查找文件。
设计的测试用例可以直接访问配置文件。 只需针对服务器调用Get()和post()方法即可获得响应。
CherryPy - Deployment Of Application
本章将更多地关注通过内置的CherryPy HTTP服务器启用的基于CherryPy的应用程序SSL。
配置 (Configuration)
Web应用程序中需要不同级别的配置设置 -
Web server - 链接到HTTP服务器的设置
Engine - 与托管引擎相关的设置
Application - 用户使用的应用程序
部署(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 (Secure Sockets Layer) 。 要启用SSL支持,必须满足以下要求 -
- 在用户的环境中安装PyOpenSSL包
- 在服务器上拥有SSL证书和私钥
创建证书和私钥
让我们来处理证书和私钥的要求 -
- 首先,用户需要私钥 -
openssl genrsa -out server.key 2048
- 此密钥不受密码保护,因此具有弱保护。
- 将发出以下命令 -
openssl genrsa -des3 -out server.key 2048
该程序将需要密码。 如果您的OpenSSL版本允许您提供空字符串,请执行此操作。 否则,输入默认密码,然后将其从生成的密钥中删除,如下所示 -
openssl rsa -in server.key -out server.key
- 证书的制作如下 -
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()
下一步是启动服务器; 如果您成功,您将在屏幕上看到以下消息 -
HTTP Serving HTTPS on https://localhost:8443/