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()
下一步是啓動伺服器;如果成功,您將在螢幕上看到以下消息−