Tornado Web 應(yīng)用程序通常由一個(gè)或多個(gè) RequestHandler子類(lèi),一個(gè)Application將傳入請(qǐng)求路由到處理程序的對(duì)象和一個(gè)?main()
?啟動(dòng)服務(wù)器的函數(shù)組成。
一個(gè)最小的“hello world”示例如下所示:
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
def get(self):
self.write("Hello, world")
def make_app():
return tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
該Application對(duì)象負(fù)責(zé)全局配置,包括將請(qǐng)求映射到處理程序的路由表。
路由表是?URLSpec
?對(duì)象(或元組)的列表,每個(gè)對(duì)象(至少)包含一個(gè)正則表達(dá)式和一個(gè)處理程序類(lèi)。訂單事項(xiàng);使用第一個(gè)匹配規(guī)則。如果正則表達(dá)式包含捕獲組,這些組是路徑參數(shù),并將傳遞給處理程序的 HTTP 方法。如果字典作為 的第三個(gè)元素傳遞URLSpec,它提供將傳遞給 的初始化參數(shù)RequestHandler.initialize。最后,URLSpec可能有一個(gè)名稱(chēng),這將允許它與 一起使用 RequestHandler.reverse_url。
例如,在這段代碼中,根URL?/
?被映射到?MainHandler
?,格式為?/story/
?后跟數(shù)字的URL被映射到?StoryHandler
?。該數(shù)字(作為字符串)傳遞給?StoryHandler.get
?
class MainHandler(RequestHandler):
def get(self):
self.write('<a href="%s">link to story 1</a>' %
self.reverse_url("story", "1"))
class StoryHandler(RequestHandler):
def initialize(self, db):
self.db = db
def get(self, story_id):
self.write("this is story %s" % story_id)
app = Application([
url(r"/", MainHandler),
url(r"/story/([0-9]+)", StoryHandler, dict(db=db), name="story")
])
Application構(gòu)造函數(shù)接受許多關(guān)鍵字參數(shù),這些參數(shù)可用于自定義應(yīng)用程序的行為并啟用可選功能;查看Application.settings的完整列表。
Tornado Web 應(yīng)用程序的大部分工作都是在RequestHandler. 處理程序子類(lèi)的主要入口點(diǎn)是一個(gè)以正在處理的 HTTP 方法命名的方法:?get()
?、 ?post()
?等。每個(gè)處理程序可以定義一個(gè)或多個(gè)這些方法來(lái)處理不同的 HTTP 操作。如上所述,將使用與匹配的路由規(guī)則的捕獲組對(duì)應(yīng)的參數(shù)調(diào)用這些方法。
在處理程序中,調(diào)用RequestHandler.render或RequestHandler.write等方法以生成響應(yīng)。?render()
?按名稱(chēng)加載Template,并用給定的參數(shù)呈現(xiàn)它。?write()
?用于非基于模板的輸出;它接受字符串、字節(jié)和字典(dict將被編碼為JSON)。
RequestHandler中的許多方法被設(shè)計(jì)為在子類(lèi)中重寫(xiě),并在整個(gè)應(yīng)用程序中使用。通常會(huì)定義一個(gè)?BaseHandler
?類(lèi)來(lái)覆蓋write_error和get_current_user等方法,然后為所有特定的處理程序子類(lèi)化自己的?BaseHandler
?而不是RequestHandler。
請(qǐng)求處理程序可以通過(guò)?self.request
?訪問(wèn)表示當(dāng)前請(qǐng)求的對(duì)象。有關(guān)屬性的完整列表,請(qǐng)參見(jiàn)HTTPServerRequest的類(lèi)定義。
HTML表單使用的格式的請(qǐng)求數(shù)據(jù)將被解析,并通過(guò)get_query_argument和get_body_argument等方法提供。
class MyFormHandler(tornado.web.RequestHandler):
def get(self):
self.write('<html><body><form action="/myform" method="POST">'
'<input type="text" name="message">'
'<input type="submit" value="Submit">'
'</form></body></html>')
def post(self):
self.set_header("Content-Type", "text/plain")
self.write("You wrote " + self.get_body_argument("message"))
由于HTML表單編碼對(duì)于參數(shù)是單個(gè)值還是包含一個(gè)元素的列表是不明確的,RequestHandler有不同的方法來(lái)允許應(yīng)用程序指示它是否需要列表。對(duì)于列表,請(qǐng)使用get_query_arguments和get_body_arguments,而不是它們的單數(shù)對(duì)應(yīng)項(xiàng)。
通過(guò)表單上傳的文件在?self.request.files
?中可用,它將名稱(chēng)(HTML ?<input type="file">
?元素的名稱(chēng))映射到文件列表。每個(gè)文件都是?{"filename":...,"content_type":...,"body":...}
?格式的字典。?files
?對(duì)象僅在使用表單包裝器(即?multipart/form-data
?內(nèi)容類(lèi)型)上載文件時(shí)存在;如果未使用此格式,則?self.request.body
?中可獲得原始上傳數(shù)據(jù)。默認(rèn)情況下,上傳的文件在內(nèi)存中完全緩沖;如果需要處理太大而無(wú)法輕松保存在內(nèi)存中的文件,請(qǐng)參閱stream_request_body類(lèi)裝飾器。
在demos目錄中,file_receiver.py顯示了接收文件上傳的兩種方法。
由于HTML表單編碼的特殊性(例如,單數(shù)和復(fù)數(shù)參數(shù)之間的模糊性),Tornado不嘗試將表單參數(shù)與其他類(lèi)型的輸入統(tǒng)一起來(lái)。特別是,我們不解析JSON請(qǐng)求體。希望使用JSON而不是表單編碼的應(yīng)用程序可能會(huì)重寫(xiě)prepare來(lái)解析其請(qǐng)求:
def prepare(self):
if self.request.headers.get("Content-Type", "").startswith("application/json"):
self.json_args = json.loads(self.request.body)
else:
self.json_args = None
除了?get()
?/?post()
?等,RequestHandler中的某些其他方法被設(shè)計(jì)為在必要時(shí)被子類(lèi)重寫(xiě)。每次請(qǐng)求時(shí),都會(huì)進(jìn)行以下順序的調(diào)用:
initialize
?通常應(yīng)該只保存?zhèn)鬟f給成員變量的參數(shù);它可能不會(huì)產(chǎn)生任何輸出或調(diào)用方法,例如 send_errorprepare
?。?prepare
?可以產(chǎn)生輸出;如果它調(diào)用finish或?redirect
?等等方法,處理將在此停止get()
?、?post()
?、?put()
?等等。如果URL正則表達(dá)式包含捕獲組,則將它們作為參數(shù)傳遞給此方法get()
?或另一個(gè) HTTP 方法返回之后。RequestHandler文件中記錄了所有設(shè)計(jì)為覆蓋的方法。一些最常用的重寫(xiě)方法包括:
Server
?表頭)如果處理程序引發(fā)異常,Tornado將調(diào)用RequestHandler.write_error生成錯(cuò)誤頁(yè)面。tornado.web.HTTPError可用于生成指定的狀態(tài)代碼;所有其他異常都返回500狀態(tài)。
默認(rèn)錯(cuò)誤頁(yè)面包括調(diào)試模式下的堆棧跟蹤和錯(cuò)誤的單行描述(例如“500:內(nèi)部服務(wù)器錯(cuò)誤”)。要生成自定義錯(cuò)誤頁(yè),請(qǐng)重寫(xiě)RequestHandler.write_error(可能在所有處理程序共享的基類(lèi)中)。這種方法通??梢酝ㄟ^(guò)write和render等方法產(chǎn)生輸出。如果錯(cuò)誤是由異常引起的,則?exc_info
?將作為關(guān)鍵字參數(shù)傳遞(請(qǐng)注意,此異常不能保證是sys.exc_info中的當(dāng)前異常,因此?write_error
?必須使用例如traceback.format_exception而不是traceback.format_exc)
也可以從常規(guī)處理程序方法生成錯(cuò)誤頁(yè)面,而不是?write_error
?通過(guò)調(diào)用 set_status、編寫(xiě)響應(yīng)和返回。在簡(jiǎn)單返回不方便的情況下,tornado.web.Finish可能會(huì)引發(fā)特殊異常以終止處理程序而不調(diào)用?write_error
?
對(duì)于404錯(cuò)誤,使用?default_handler_class
?應(yīng)用程序設(shè)置。這個(gè)處理程序應(yīng)該覆蓋prepare,而不是像???get()??
?這樣更具體的方法,這樣它就可以與任何HTTP方法一起工作。它應(yīng)該如上所述生成錯(cuò)誤頁(yè)面:通過(guò)引發(fā)?HTTPError(404)
?并覆蓋?write_error
?,或者調(diào)用?self.set_status(404)
?并直接在?prepare()
?中生成響應(yīng)。
在Tornado中,有兩種主要的重定向請(qǐng)求的方法:RequestHandler.redirect和RedirectHandler
可以在?self.redirect()
?方法中使用RequestHandler將用戶重定向到其他地方。還有一個(gè)可選參數(shù)?permanent
?,可用于指示重定向被視為永久性的。?permanent
?的默認(rèn)值為?False
?,這將生成一個(gè)?302 Found
?的HTTP響應(yīng)代碼,適用于在成功的?POST
?請(qǐng)求后重定向用戶。如果?permanent
?為?True
?,則使用?301 Moved permanually
?HTTP響應(yīng)代碼,這有助于以SEO友好的方式重定向到頁(yè)面的規(guī)范URL
RedirectHandler允許您直接在Application路由表中配置重定向。例如,要配置單個(gè)靜態(tài)重定向:
app = tornado.web.Application([
url(r"/app", tornado.web.RedirectHandler,
dict(url="http://itunes.apple.com/my-app-id")),
])
RedirectHandler還支持正則表達(dá)式替換。以下規(guī)則將所有以?/pictures
?開(kāi)頭的請(qǐng)求重定向到前綴?/photos
?:
app = tornado.web.Application([
url(r"/photos/(.*)", MyPhotoHandler),
url(r"/pictures/(.*)", tornado.web.RedirectHandler,
dict(url=r"/photos/{0}")),
])
與RequestHandler.redirect不同,RedirectHandler默認(rèn)使用永久重定向。這是因?yàn)槁酚杀碓谶\(yùn)行時(shí)不會(huì)更改,并且被認(rèn)為是永久的,而在處理程序中找到的重定向可能是其他可能更改的邏輯的結(jié)果。要使用RedirectHandler發(fā)送臨時(shí)重定向,請(qǐng)?jiān)?a rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" target="_blank">RedirectHandler初始化參數(shù)中添加?permanent=False
?
某些處理程序方法(包括?prepare()
?和HTTP的?get()
?/?post()
?方法等)可能會(huì)被重寫(xiě)為協(xié)同路由,以使處理程序異步。
例如,下面是一個(gè)使用協(xié)同程序的簡(jiǎn)單處理程序:
class MainHandler(tornado.web.RequestHandler):
async def get(self):
http = tornado.httpclient.AsyncHTTPClient()
response = await http.fetch("http://friendfeed-api.com/v2/feed/bret")
json = tornado.escape.json_decode(response.body)
self.write("Fetched " + str(len(json["entries"])) + " entries "
"from the FriendFeed API")
更多建議: