- 論壇徽章:
- 0
|
注:本文由gashero翻譯,歡迎轉(zhuǎn)載,轉(zhuǎn)載前情確保同意英文原版的版權(quán)聲明。因本人英語水平有限,文中有錯誤之處歡迎指出,意見發(fā)送到harry.python@gmail.com。本文不定期更新,請關(guān)注"河邊的小屋"(http://blog.csdn.net/gashero)來查看最新翻譯版本。翻譯全程特別感謝"畫鬢如霜"的支持,沒有你的愛我無法完成這一切。也感謝python-chinese郵件列表上朋友的支持!
第一章簡介
1.1性能
使用mod_python的主要優(yōu)勢在于比傳統(tǒng)CGI更高的性能。一個測試,使用在Pentium 1.2GHz的機器上運行Red Hat Linux 7.3。使用4種類型的腳本,基于標準的CGI導(dǎo)入模塊(以典型的Python CGI腳本開始),然后輸出'Hello!',測試10000次請求作為基準。
標準CGI: 23 次請求/秒
mod_python CGI處理器: 385 次請求/秒
mod_python 發(fā)布處理器: 476 次請求/秒
mod_python 處理器: 1203 次請求/秒
1.2可移植性
apache是按照階段處理請求的(比如:讀取請求、處理請求頭、檢查存取等)。這些階段可以分別用處理器調(diào)用的函數(shù)來實現(xiàn)。傳統(tǒng)上,使用C語言編寫處理器模塊。mod_python提供了使用Python拜你些apache處理器擴展apache功能的方法。更多的apache請求處理過程,參考"Apache API Notes",或者參考"Mod_python-Integrating Python with Apache"文件。
為了方便的從CGI移植,標準的mod_python處理器提供了CGI模擬環(huán)境,允許用戶不修改遺留下來的腳本,而在大多數(shù)時候無需進行任何修改。
參考:
http://dev.apache.org
apache開發(fā)者資源
http://www.modpython.org/python10/
mod_python-整合Python和Apache,出現(xiàn)在Python 10(?)
1.3歷史
mod_python起源于Httpdapy項目(1997)。很久以后Httpdapy才被叫做mod_python,因為Httpdapy并不是特定用于apache服務(wù)器的。Httpdapy設(shè)計成跨平臺的,而實際上主要從Netscape服務(wù)器開始(追溯到1997年的Nsapy)。
摘錄自Httpdapy項目的README文件的描述將Python嵌入到apache服務(wù)器的挑戰(zhàn)與解決方法。
""" #小字體
在我多年前開發(fā)第一個WEB應(yīng)用程序時就發(fā)現(xiàn)CGI訪問數(shù)據(jù)庫非常慢,因為每次點擊請求都會裝入解釋器并執(zhí)行數(shù)MB的數(shù)據(jù)。數(shù)據(jù)庫往往都很大,并將大量時間浪費在數(shù)據(jù)庫的連接/認證等"意義重大"的事情上,像DNS查詢、編碼與解碼、內(nèi)存分配等等。在應(yīng)用提速的壓力下,我嘗試過使用Python和多種工具的綜合使用。我并不迷信微軟的ASP,又被Netscape的性能和滿是臭蟲而郁悶。"Cold Fusion"(冷聚變)看起來有希望,但我稍后學(xué)會了HTML類標簽的書寫方式,可讀性跟匯編有一拼。比如PHP。但是我真的很想用Python來寫東西。
就在同時有關(guān)Python互聯(lián)網(wǎng)編程的書籍出版了,其中將Python嵌入到Netscape服務(wù)器的方式立即引起了我的注意。我在我的項目中使用了這個例子,并在稍后開發(fā)了我自己的改進版,叫做Nsapy,并在WindowsNT和Solaris上編譯。
盡管Nsapy僅能工作在Netscape服務(wù)器上,但是出于靈活通用的面向?qū)ο笤O(shè)計,在Python精靈中,很容易移植到其他的WEB服務(wù)器。
后來,曾經(jīng)流行的Netscape服務(wù)器掛了,我就將Nsapy移植到最流行的服務(wù)器apache上。所以從Nsapy衍生出了Httpdapy。
"""
繼續(xù)這個傳奇,你會想到將Httpdapy移植到其他服務(wù)器上,實際上他們比預(yù)想要復(fù)雜而且枯燥。
反之,提供一個類似于Perl語言的apache擴展mod_perl一樣或更好性能的部件會更有意思。
俱往矣,mod_python的第一個版本發(fā)布于2000年5月。
完成...
第二章安裝
注意:獲得關(guān)于安裝的幫助和其他問題的最好地方是mod_python的郵件列表。可以發(fā)送標題為"subscribe"的郵件到mod_python-request@modpython.org。
2.1先決條件
• Python 2.2.1或更新的版本,早起版本將無法使用。
• apache 2.0.40或更新的版本,如果要使用apache 1.3.x,請使用mod_python的版本2.7.x。
編譯mod_python需要有apache和Python的包含文件,并且確保安裝了Python標準庫。如果你從源代碼安裝了Python和apache,那么你已經(jīng)擁有了這些了。如果你使用了預(yù)打包軟件,如RPM或其他方式則只有二進制版本,而沒有源碼。通常apache和Python的包含文件和庫文件在各自的"development"包中。如果你不確定擁有這些重要文件,請從源碼安裝Python和apache,或者閱讀你系統(tǒng)的文檔以了解如何獲得開發(fā)包。
2.2編譯
有兩種鏈接apache模塊的方式:靜態(tài)的和DSO方式。
DSO方式現(xiàn)在非常流行,并推薦用于mod_python的安裝。模塊被編譯成共享庫,并在運行時動態(tài)裝入。
DSO方式的優(yōu)勢在于安裝模塊時無需重新編譯apache。關(guān)于DSO機制的詳細信息參見http://httpd.apache.org/docs-2.0/dso.html。
當前版本的mod_python僅支持DSO方式。
靜態(tài)鏈接是一種較老的方式,比動態(tài)連接的方式支持更多的平臺,但是較少使用。主要的缺陷是必須要重新編譯apache,在很多情況下并不是一個好的選擇。
2.2.1運行./configure
./configure腳本將會分析你的運行環(huán)境,并創(chuàng)建自定義的Make文件用于你的系統(tǒng)。使用autoconf生成的./configure包含如下內(nèi)容:
• 查看apxs程序是否存在。這個程序作為apache標準發(fā)行版的一部分提供DSO支持。如果找不到則無法實現(xiàn)DSO功能。使用--with-apxs指定選項:
$ ./configure --with-apxs=/usr/local/apache/bin/apxs
強烈建議使用這個選項。
• 檢查Python版本,并嘗試找到libpython參數(shù)變量的二進制發(fā)行版。缺省時可以在Path變量中找到python。如果找到的首個python二進制版本不適合mod_python,則可以手動指定python的路徑使用--with-python,如:
$ ./configure --with-python=/usr/local/bin/python2.3
• 設(shè)置mod_python保留的互斥鎖數(shù)量。在某些系統(tǒng)中,互斥鎖是一種有限的資源。增加最大互斥鎖數(shù)量將會增加使用session鎖定的性能。缺省值是8,一個性能不錯的數(shù)值是32。使用-with-max-locks選項:
$ ./configure --with-max-locks=32
這個選項是在3.2.0版本開始提供的。
• 嘗試查找flex并確定版本。如果PATH中找不到flex則configure會出錯。如果版本不對則會給出警告。一般可以忽略這個警告,除非需要重新創(chuàng)建src/psp_parser.c。剖析器(parser)會被PSP調(diào)用,使用flex的C語言書寫。要求的版本是2.5.31,在大多數(shù)平臺上2.5.4并不合適。所以已經(jīng)源碼里已經(jīng)包含了一個psp_parser.c的副本。如果需要編譯src/psp_parser.c則需要獲取正確版本的flex。如果PATH中的flex版本有誤,則可用-with-flex選項:
$ ./configure --with-flex=/usr/local/bin/flex
這是3.2.0版本中的新特性
• 構(gòu)建mod_python文檔時需要用到python的源代碼?梢匀绻恍枰臋n,可以忽略這個選項。如果需要則用--with-python-src選項:
$ ./configure --with-python-src=/usr/src/python2.3
這個是3.2.0版本中的新特性
2.2.2運行make
開始構(gòu)建過程,簡單的運行如下即可:
$ make
2.3安裝
2.3.1運行make install
這個安裝過程必須在root用戶下完成:
$ su
# make install
這將會簡單的將二進制版本復(fù)制到apache的libexec目錄。
并且會安裝python-libraries到site-packages并編譯他們。
如果你想只安裝python庫或者只安裝DSO,可以用如下make目標:
# make install_py_lib
# make install_dso
2.3.2配置apache
按照DSO模式安裝的apache,需要在httpd.conf中加入啟動mod_python的句子:
LoadModule python_module libexec/mod_python.so
實際的mod_python.so路徑可能有所變化,但是make install將會顯示這個文件的確切路徑。
2.4測試
注意次部分內(nèi)容僅適用于3.x版本,如果使用2.7.x版本,你需要找到更適合的文檔。
• 創(chuàng)建一個在WEB站點可見的目錄,如htdocs/test。
• 在httpd.conf或者.htaccess文件中添加如下內(nèi)容。如果是在.htaccess文件中,則無需<Directory>標簽。并且確保httpd.conf文件中的AllowOverride目標至少包含F(xiàn)ileInfo,缺省是None,將會無法工作。
<Directory /APACHEHOME/htdocs/test>
AddHandler mod_python .py
PythonHandler mptest
PythonDebug On
</Directory>
• 重定向所有以.py結(jié)尾的URL到mod_python處理器。mod_python收到請求之后查找合適的處理器來處理請求。這里有個簡單的自定義處理器叫mptest。我們看看如何定義這個處理器。
• 此時如果修改了主配置文件httpd.conf則需要重啟apache來使之生效。
• 編輯mptest.py文件在htdocs/test目錄。
from mod_python import apache
def handler(req):
req.content_type='text/plain'
req.write("Hello, world!")
return apache.OK
• 指向URL路徑到mptest.py。將會看到"Hello, world!"。如果看不到則參考故障處理。
• 依照配置文件的規(guī)則,指定任何.py文件都會最終指向mptest.py做處理。因為已經(jīng)明確的指定了mptest做處理器。如果需要用不同的處理器處理不同的文件則需要更高層的處理器,比如publisher發(fā)布器、mpservlets或vampire。這些都是動態(tài)裝入的處理器。
• 如果都運行無誤則轉(zhuǎn)入第三章,入門。
參考:
http://home.comcast.net/d.popowich/mpservlets
http://www.dscpl.com.au/projects/vampire
2.5故障處理
如果出現(xiàn)問題,可以按照如下的處理:
• 檢查錯誤輸出
• 檢查服務(wù)器錯誤日志
• 單處理執(zhí)行apache
$ ./httpd -X
這樣將會顯示更多有用信息
• 從mod_python3.2.0開始,可以使用mod_python.testhandler來診斷你的配置。添加到httpd.conf文件:
<Location /mpinfo>
SetHandler mod_python
PythonHandler mod_python.testhandler
</Location>
這時指向你的/mpinfo的URL則會顯示一些信息幫助處理mod_python的問題。
• 在mod_python郵件列表提問,并確保提供如下信息:
mod_python版本
操作系統(tǒng)類型、名字、版本號
Python版本、非常規(guī)的編輯選項
apache服務(wù)器版本
相關(guān)的apache配置,.htaccess
相關(guān)的Python代碼
完成...
第三章指南
3.1使用發(fā)布器(Publisher)的快速例子
這一節(jié)提供無需太多細節(jié)的發(fā)布器指南。更多如何使用mod_python處理器的細節(jié)將在以后解釋。
發(fā)布器(publisher)提供了發(fā)布mod_python標準模塊的方式。需要在配置文件中加入如下配置:
AddHandler mod_python .py
PythonHandler mod_python.publisher
PythonDebug On
下例會返回簡單的表單數(shù)據(jù)。詢問姓名、電子郵件、注釋之后將會給管理員發(fā)郵件。這個簡單的應(yīng)用程序由兩個文件組成:form.html用于提交數(shù)據(jù),form.py用于處理表單動作。
如下是表單:
<html>
Please provide feedback below:
<p>
<form action="form.py/email" method="POST">
Name: <input type="text" name="name"><br>
Email: <input type="text" name="email"><br>
Comment: <textarea name="comment" rows=4 cols=20></textarea><br>
<input type="submit">
</form>
</html>
注意表單的action屬性指向form.py/email調(diào)用,如下創(chuàng)建form.py,如下:
import smtplib
WEBMASTER="webmaster" #管理員電郵
SMTP_SERVER="localhost" #本機SMTP服務(wù)器
def email(req,name,email,comment):
#一定要確保用戶提供了所有的參數(shù)
if not(name and email and comment):
return "缺少必要的參數(shù)"
#創(chuàng)建消息文本
msg=""" \
From: %s
Subject: feedback
To: %s
I have the following comment:
%s
Thank You,
%s
""" % (email,WEBMASTER,comment,name)
#發(fā)送信息
conn=smtplib.SMTP(SMTP_SERVER)
conn.sendmail(email,[WEBMASTER],msg)
conn.quit()
#提供返回頁面
s="""\
<html>
Dear %s,<br>
Thank you for your kind comments, we
will get back to you shortly.
</html>""" % name
return name
當用戶點擊提交按鈕時,發(fā)布器將會裝入email函數(shù)到form模塊,傳遞表單字段作為關(guān)鍵字參數(shù)。也會傳遞請求對象到req。
注意逆必須要有req參數(shù)。發(fā)布器已經(jīng)可以很聰明的傳遞必要的參數(shù)。函數(shù)的返回值將被發(fā)送到客戶端瀏覽器。
即使使用發(fā)布器可以非常簡單的處理,但是程序仍然可以利用mod_python的強大功能,比如調(diào)用請求對象。當然也可以調(diào)用本地的mod_python處理器來完成大量的工作。比如設(shè)置HTML頭路由req.headers_out;返回錯誤拋出apache.SERVER_ERROR異常;從客戶端的重定向讀寫文件req.write()和req.read(),等等。
閱讀6.1節(jié)了解更多關(guān)于發(fā)布器的詳細信息。
3.2apache處理器概覽
節(jié)標題翻譯有誤,應(yīng)為"快速學(xué)習(xí)apache如何處理請求"。
如果你想要深入鉆研mod_python的功能,需要理解什么是處理器。
apache分階段(phase)處理請求。比如第一個階段是用戶認證,之后是檢驗用戶是否有權(quán)訪問特定的文件,然后是讀取文件并發(fā)送到客戶端。一個典型的靜態(tài)文件請求包含三個階段:1.翻譯URI到文件位置2.讀取文件并發(fā)送到客戶端3.記錄請求日志。更復(fù)雜的處理依賴于配置文件。
一個處理器就是初始處理某個階段的函數(shù)。同一個階段可以有多于一個處理器進行處理,被叫做apache序列。對應(yīng)每個階段有個缺省的apache處理器(大多數(shù)只做缺省動作或者什么都不作)。然后由其他的apache模塊提供處理器,比如mod_python。
mod_python提供了apache每一個重要的處理器。mod_python處理器缺省時不會做任何事情,除非用特定的配置文件標志。這些標志以"Python"開始并以"Handler"結(jié)尾(如:PythonAuthenHandler),指定Python函數(shù)來處理指定的階段。所以mod_python的主函數(shù)只是作為發(fā)報機的角色連接apache處理器和Python函數(shù)。
最常用的處理器是PythonHandler。它處理含有上下文的請求。因為它沒有名字,所以有時也成為通用處理器。這個處理器的apache缺省行為是讀取文件并發(fā)送到客戶端。大多數(shù)應(yīng)用應(yīng)該重寫這個處理器。
3.3mod_python做了什么
我們假設(shè)有如下配置:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonDebug On
</Directory>
所以還需要一個如下文件,'/mywebdir/myscript.py'如下:
from mod_python import apache
def handler(req):
req.content_type="text/plain"
req.write("Hello World!")
return apache.OK
如下的事情將會發(fā)生:AddHandler標志告訴apache所有的以.py結(jié)尾的'/mywebdir'下或其子目錄下的文件請求都由mod_python負責(zé)處理。'PythonHandler myscript'標志告訴mod_python通用處理器在myscript腳本。'PythonDebug On'標志告訴mod_python如果發(fā)生錯誤,則把錯誤信息輸出到客戶端,便于開發(fā)。
當請求到來時,apache開始分步驟處理請求并講請求發(fā)送到mod_python。mod_python處理器檢查配置獲取處理器。在本例,我們除了通用處理器之外沒有調(diào)用其他東西。當讀取配置到'PythonHandler myscript'時,會發(fā)生下面的事情:
1.如果沒有做過,假設(shè)預(yù)設(shè)目錄已經(jīng)存在于sys.path中。
2.嘗試按名字導(dǎo)入模塊myscript。注意子目錄是不在sys.path中的,如果需要只能按照包名的方式調(diào)用。
3.在myscript中查找函數(shù)handler
4.調(diào)用這個函數(shù)并傳遞請求對象(關(guān)于請求對象的更多東西在后面)
5.在這里我們細致研究一下腳本:
from mod_python import apache
導(dǎo)入apache模塊來獲取apache的接口。大多數(shù)mod_python程序需要有這一行。
def handler(req):
這是處理器函數(shù)的聲明。叫做'handler'是因為mod_python按照配置標志尋找函數(shù)。將配置標志轉(zhuǎn)換成小寫,然后去掉'python'即可。這樣'PythonHandler'就成了'handler'。當然也可以用其他的名字,但是需要用'::'來分隔函數(shù)名,比如一個處理器函數(shù)叫'spam',那么配置標志就是'PythonHandler myscript::spam'
注意,處理器必須包含一個請求對象參數(shù)。請求對象提供了關(guān)于請求的大量信息,比如客戶端的IP,請求頭,URL等。向客戶端發(fā)送信息也需要用到請求對象,這里是沒有'response'對象的。
req.content_type="text/plain"
設(shè)置文檔MIME類型為'text/plain'。缺省的是'text/html',但是如果處理器沒有打算返回html,那么'text/plain'更恰當(appropriate)一些。特別注意:需要在req.write方法之前調(diào)用如上語句,因為一旦調(diào)用req.write,HTTP響應(yīng)頭就被發(fā)送出去了,其后的HTTP響應(yīng)頭的改變都會忽略。
req.write("Hello World!")
將會把字符串寫入到客戶端。
return apache.OK
告知apache,請求處理完成并成功。如果沒有返回OK,則apache會自動返回為apache.HTTP_INTERNAL_SERVER_ERROR或return apache.HTTP_FORBIDDEN。當處理失敗時會在錯誤日志中記錄,并告知客戶端一點錯誤信息。
小技巧:如果你注意到,會發(fā)現(xiàn)如果請求的URL不是指向myscript.py,而只是一個.py結(jié)尾的文件,哪怕是一個不存在的文件,也可以得到相同的結(jié)果。因為服務(wù)器只是將特定結(jié)尾的處理直接交給相關(guān)模塊的,而并不要求那一定是一個存在的文件。
3.4更復(fù)雜的例子-認證
現(xiàn)在,你知道寫一個處理器多么的簡單,下面我們來顯示一個更復(fù)雜的例子。
如果需要用密碼來保護一個目錄。比如登錄名為'spam',密碼為'eggs'。
首先需要告訴apache在需要認證時調(diào)用我們的認證處理器。加入PythonAuthenHandler標志到配置文件:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
</Directory>
因為一個模塊可以包含多個函數(shù),所以也可以在一個模塊中使用多個處理器。
然后是告知apache,使用Basic HTTP認證。僅限有效用戶進入。配置如下:
<Directory /mywebdir>
AddHandler mod_python .py
PythonHandler myscript
PythonAuthenHandler myscript
PythonDebug On
AuthType Basic
AuthName "Restricted Area"
require valid-user
</Directory>
然后在myscript.py中寫認證函數(shù),一個簡單認證函數(shù)如下:
from mod_python import apache
def authenhandler(req):
pw=req.get_basic_auth_pw()
user=req.user
if user=="spam" and pw=="eggs":
return apache.OK
else:
return apache.HTTP_UNAUTHORIZED
如下是逐行解釋:
def authenhandler(req):
認證函數(shù)的聲明,至于為什么叫這個名字,自己可以參考命名規(guī)則。
pw=req.get_basic_auth_pw()
這里獲取密碼。basic HTTP認證采用base64編碼發(fā)送到服務(wù)器。這個函數(shù)返回的直接就是密碼了。注意必須在獲取用戶名之前先獲取密碼。
user=req.user
獲取用戶名
if user=="spam" and pw=="eggs":
return apache.OK
對比用戶名和密碼的值,如果正確返回告知驗證成功,并進入下一個階段的處理。在本例里下一個階段是handler()。
else:
return apache.HTTP_UNAUTHORIZED
告知apache驗證失敗。這通常會導(dǎo)致客戶端瀏覽器彈出對話框要求用戶名和密碼。
實測:
發(fā)現(xiàn)我使用的httpd-2.0.55提示驗證類型無效,一共兩種驗證類型,一種是Basic一種是Digest,都是不允許的。就是按照如上例子。
終于實驗成功了,最上面的配置必須寫在httpd.conf中才會有效,寫在.htaccess中無效。無論是否指定了AllowOverride FileInfo都是。這樣進入一個目錄之后會彈出系統(tǒng)的對話框提示輸入用戶名密碼。驗證成功后只要瀏覽器不關(guān)閉就可以繼續(xù)進入這個目錄,但是關(guān)閉后就需要再次驗證。
3.5你自己的404處理器
在某些時候,如果希望返回404(HTTP_NOT_FOUND)或者其他非200的結(jié)果到客戶端,這里有個竅門。如果從你的處理器返回HTTP_NOT_FOUND, apache將會生成錯誤頁。但是卻未必是你喜歡的錯誤頁。
這時,你只要設(shè)置req.status=apache.HTTP_NOT_FOUND,提交你的頁面,然后返回apache.OK就可以了:
from mod_python import apache
def handler(req):
if req.filename[-17:]=='apache-error.html':
#放行apache的錯誤頁
if req.filename[-18:]=='handler-error.html':
#使用自己的錯誤頁
req.status=apache.HTTP_NOT_FOUND
pagebuffer='頁面不存在'
else:
#使用文件內(nèi)容
pagebuffer=open(req.filename,'r').read()
#輸出錯誤頁
req.write(pagebuffer)
return(apache.OK)
完成...
[ 本帖最后由 wang52114978 于 2006-7-25 11:11 編輯 ] |
|