打開你寫python代碼用的編輯器,不要問為什么,把下面的代碼一個字不差地錄入進(jìn)去,并命名保存為hello.py(目錄自己任意定)。
#!/usr/bin/env python
#coding:utf-8
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', welcome you to read: www.itdiffer.com')
if __name__ == "__main__":
tornado.options.parse_command_line()
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(options.port)
tornado.ioloop.IOLoop.instance().start()
進(jìn)入到保存hello.py文件的目錄,執(zhí)行:
$ python hello.py
用python運(yùn)行這個文件,其實(shí)就已經(jīng)發(fā)布了一個網(wǎng)站,只不過這個網(wǎng)站太簡單了。
接下來,打開瀏覽器,在瀏覽器中輸入:http://localhost:8000,得到如下界面:
我在ubuntu的shell中還可以用下面方式運(yùn)行:
$ curl http://localhost:8000/
Hello, welcome you to read: www.itdiffer.com
$ curl http://localhost:8000/?greeting=Qiwsir
Qiwsir, welcome you to read: www.itdiffer.com
此操作,讀者可以根據(jù)自己系統(tǒng)而定。
恭喜你,邁出了決定性一步,已經(jīng)可以用Tornado發(fā)布網(wǎng)站了。在這里似乎沒有做什么部署,只是安裝了Tornado。是的,不需要多做什么,因?yàn)門ornado就是一個很好的server,也是一個開發(fā)框架。
下面以這個非常簡單的網(wǎng)站為例,對用tornado做的網(wǎng)站的基本結(jié)構(gòu)進(jìn)行解釋。
任何一個網(wǎng)站都離不開Web服務(wù)器,這里所說的不是指那個更計(jì)算機(jī)一樣的硬件設(shè)備,是指里面安裝的軟件,有時(shí)候初次接觸的看官容易搞混。就來偉大的維基百科都這么說:
有時(shí),這兩種定義會引起混淆,如Web服務(wù)器。它可能是指用于網(wǎng)站的計(jì)算機(jī),也可能是指像Apache這樣的軟件,運(yùn)行在這樣的計(jì)算機(jī)上以管理網(wǎng)頁組件和回應(yīng)網(wǎng)頁瀏覽器的請求。
在具體的語境中,看官要注意分析,到底指的是什么。
關(guān)于Web服務(wù)器比較好的解釋,推薦看看百度百科的內(nèi)容,我這里就不復(fù)制粘貼了,具體可以點(diǎn)擊連接查閱:WEB服務(wù)器
在WEB上,用的最多的就是輸入網(wǎng)址,訪問某個網(wǎng)站。全世界那么多網(wǎng)站網(wǎng)頁,如果去訪問,怎么能夠做到彼此互通互聯(lián)呢。為了協(xié)調(diào)彼此,就制定了很多通用的協(xié)議,其中http協(xié)議,就是網(wǎng)絡(luò)協(xié)議中的一種。關(guān)于這個協(xié)議的介紹,網(wǎng)上隨處就能找到,請自己google.
網(wǎng)上偷來的一張圖(從哪里偷來的,我都告訴你了,多實(shí)在呀。哈哈。),顯示在下面,簡要說明web服務(wù)器的工作過程
偷個徹底,把原文中的說明也貼上:
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
這四個都是Tornado的模塊,在本例中都是必須的。它們四個在一般的網(wǎng)站開發(fā)中,都要用到,基本作用分別是:
讀者看到這里可能有點(diǎn)莫名其妙,對一些屬于不理解。沒關(guān)系,你可以先不用管它,如果愿意管,就把不理解屬于放到google立面查查看。一定要硬著頭皮一字一句地讀下去,隨著學(xué)習(xí)和實(shí)踐的深入,現(xiàn)在不理解的以后就會逐漸領(lǐng)悟理解的。
還有一個模塊引入,是用from...import完成的
from tornado.options import define, options
define("port", default=8000, help="run on the given port", type=int)
這兩句就顯示了所謂“命令行解析模塊”的用途了。在這里通過tornado.options.define()
定義了訪問本服務(wù)器的端口,就是當(dāng)在瀏覽器地址欄中輸入http:localhost:8000
的時(shí)候,才能訪問本網(wǎng)站,因?yàn)閔ttp協(xié)議默認(rèn)的端口是80,為了區(qū)分,我在這里設(shè)置為8000,為什么要區(qū)分呢?因?yàn)槲业挠?jì)算機(jī)或許你的也是,已經(jīng)部署了別(或許是Nginx、Apache)服務(wù)器了,它的端口是80,所以要區(qū)分開(也可能是故意不用80端口),并且,后面我們還會將tornado和Nginx聯(lián)合起來工作,這樣兩個服務(wù)器在同一臺計(jì)算機(jī)上,就要分開嘍。
class IndexHandler(tornado.web.RequestHandler):
def get(self):
greeting = self.get_argument('greeting', 'Hello')
self.write(greeting + ', welcome you to read: www.itdiffer.com')
所謂“請求處理”程序類,就是要定義一個類,專門應(yīng)付客戶端(就是你打開的那個瀏覽器界面)向服務(wù)器提出的請求(這個請求也許是要讀取某個網(wǎng)頁,也許是要將某些信息存到服務(wù)器上),服務(wù)器要有相應(yīng)的程序來接收并處理這個請求,并且反饋某些信息(或者是針對請求反饋所要的信息,或者返回其它的錯誤信息等)。
于是,就定義了一個類,名字是IndexHandler,當(dāng)然,名字可以隨便取了,但是,按照習(xí)慣,類的名字中的單詞首字母都是大寫的,并且如果這個類是請求處理程序類,那么就最好用Handler結(jié)尾,這樣在名稱上很明確,是干什么的。
類IndexHandler繼承tornado.web.RequestHandler
,其中再定義get()
和post()
兩個在web中應(yīng)用最多的方法的內(nèi)容(關(guān)于這兩個方法的詳細(xì)解釋,可以參考:HTTP GET POST的本質(zhì)區(qū)別詳解,作者在這篇文章中,闡述了兩個方法的本質(zhì))。
在本例中,只定義了一個get()
方法。
用greeting = self.get_argument('greeting', 'Hello')
的方式可以得到url中傳遞的參數(shù),比如
$ curl http://localhost:8000/?greeting=Qiwsir
Qiwsir, welcome you to read: www.itdiffer.com
就得到了在url中為greeting設(shè)定的值Qiwsir。如果url中沒有提供值,就是Hello.
官方文檔對這個方法的描述如下:
RequestHandler.get_argument(name, default=, []strip=True)
Returns the value of the argument with the given name.
If default is not provided, the argument is considered to be required, and we raise a MissingArgumentError if it is missing.
If the argument appears in the url more than once, we return the last value.
The returned value is always unicode.
接下來的那句self.write(greeting + ',weblcome you to read: www.itdiffer.com)'
中,write()
方法主要功能是向客戶端反饋信息。也瀏覽一下官方文檔信息,對以后正確理解使用有幫助:
RequestHandler.write(chunk)[source]
Writes the given chunk to the output buffer.
To write the output to the network, use the flush() method below.
If the given chunk is a dictionary, we write it as JSON and set the Content-Type of the response to be application/json. (if you want to send JSON as a different Content-Type, call set_header after calling write()).
if __name__ == "__main__"
,這個方法跟以往執(zhí)行python程序是一樣的。
tornado.options.parse_command_line()
,這是在執(zhí)行tornado的解析命令行。在tornado的程序中,只要import模塊之后,就會在運(yùn)行的時(shí)候自動加載,不需要了解細(xì)節(jié),但是,在main()方法中如果有命令行解析,必須要提前將模塊引入。
下面這句是重點(diǎn):
app = tornado.web.Application(handlers=[(r"/", IndexHandler)])
將tornado.web.Application類實(shí)例化。這個實(shí)例化,本質(zhì)上是建立了整個網(wǎng)站程序的請求處理集合,然后它可以被HTTPServer做為參數(shù)調(diào)用,實(shí)現(xiàn)http協(xié)議服務(wù)器訪問。Application類的__init__
方法參數(shù)形式:
def __init__(self, handlers=None, default_host="", transforms=None,**settings):
pass
在一般情況下,handlers是不能為空的,因?yàn)锳pplication類通過這個參數(shù)的值處理所得到的請求。例如在本例中,handlers=[(r"/", IndexHandler)]
,就意味著如果通過瀏覽器的地址欄輸入根路徑(http://localhost:8000
就是根路徑,如果是http://localhost:8000/qiwsir
,就不屬于根,而是一個子路徑或目錄了),對應(yīng)著就是讓名字為IndexHandler類處理這個請求。
通過handlers傳入的數(shù)值格式,一定要注意,在后面做復(fù)雜結(jié)構(gòu)的網(wǎng)站是,這里就顯得重要了。它是一個list,list里面的元素是tuple,tuple的組成包括兩部分,一部分是請求路徑,另外一部分是處理程序的類名稱。注意請求路徑可以用正則表達(dá)式書寫(關(guān)于正則表達(dá)式,后面會進(jìn)行簡要介紹)。舉例說明:
handlers = [
(r"/", IndexHandlers), #來自根路徑的請求用IndesHandlers處理
(r"/qiwsir/(.*)", QiwsirHandlers), #來自/qiwsir/以及其下任何請求(正則表達(dá)式表示任何字符)都由QiwsirHandlers處理
]
注意
在這里我使用了r"/"
的樣式,意味著就不需要使用轉(zhuǎn)義符,r后面的都表示該符號本來的含義。例如,\n,如果單純這么來使用,就以為著換行,因?yàn)榉枴癨”具有轉(zhuǎn)義功能(關(guān)于轉(zhuǎn)義詳細(xì)閱讀《字符串(1)》),當(dāng)寫成r"\n"
的形式是,就不再表示換行了,而是兩個字符,\和n,不會轉(zhuǎn)意。一般情況下,由于正則表達(dá)式和 \ 會有沖突,因此,當(dāng)一個字符串使用了正則表達(dá)式后,最好在前面加上'r'。
關(guān)于Application類的介紹,告一段落,但是并未完全講述了,因?yàn)檫€有別的參數(shù)設(shè)置沒有講,請繼續(xù)關(guān)注后續(xù)內(nèi)容。
實(shí)例化之后,Application對象(用app做為標(biāo)簽的)就可以被另外一個類HTTPServer引用,形式為:
http_server = tornado.httpserver.HTTPServer(app)
HTTPServer是tornado.httpserver里面定義的類。HTTPServer是一個單線程非阻塞HTTP服務(wù)器,執(zhí)行HTTPServer一般要回調(diào)Application對象,并提供發(fā)送響應(yīng)的接口,也就是下面的內(nèi)容是跟隨上面語句的(options.port的值在IndexHandler類前面通過from...import..設(shè)置的)。
http_server.listen(options.port)
這種方法,就建立了單進(jìn)程的http服務(wù)。
請看官牢記,如果在以后編碼中,遇到需要多進(jìn)程,請參考官方文檔說明:http://tornado.readthedocs.org/en/latest/httpserver.html#http-server
剩下最后一句了:
tornado.ioloop.IOLoop.instance().start()
這句話,總是在__main()__
的最后一句。表示可以接收來自HTTP的請求了。
以上把一個簡單的hello.py剖析。想必讀者對Tornado編寫網(wǎng)站的基本概念已經(jīng)有了。
如果一頭霧水,也不要著急,以來將上面的內(nèi)容多看幾遍。對整體結(jié)構(gòu)有一個基本了解,不要拘泥于細(xì)節(jié)或者某些詞匯含義。然后即繼續(xù)學(xué)習(xí)。
更多建議: