Tornado Web 應(yīng)用程序通常由一個或多個 RequestHandler子類,一個Application將傳入請求路由到處理程序的對象和一個?main()
?啟動服務(wù)器的函數(shù)組成。
一個最小的“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對象負責(zé)全局配置,包括將請求映射到處理程序的路由表。
路由表是?URLSpec
?對象(或元組)的列表,每個對象(至少)包含一個正則表達式和一個處理程序類。訂單事項;使用第一個匹配規(guī)則。如果正則表達式包含捕獲組,這些組是路徑參數(shù),并將傳遞給處理程序的 HTTP 方法。如果字典作為 的第三個元素傳遞URLSpec,它提供將傳遞給 的初始化參數(shù)RequestHandler.initialize。最后,URLSpec可能有一個名稱,這將允許它與 一起使用 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. 處理程序子類的主要入口點是一個以正在處理的 HTTP 方法命名的方法:?get()
?、 ?post()
?等。每個處理程序可以定義一個或多個這些方法來處理不同的 HTTP 操作。如上所述,將使用與匹配的路由規(guī)則的捕獲組對應(yīng)的參數(shù)調(diào)用這些方法。
在處理程序中,調(diào)用RequestHandler.render或RequestHandler.write等方法以生成響應(yīng)。?render()
?按名稱加載Template,并用給定的參數(shù)呈現(xiàn)它。?write()
?用于非基于模板的輸出;它接受字符串、字節(jié)和字典(dict將被編碼為JSON)。
RequestHandler中的許多方法被設(shè)計為在子類中重寫,并在整個應(yīng)用程序中使用。通常會定義一個?BaseHandler
?類來覆蓋write_error和get_current_user等方法,然后為所有特定的處理程序子類化自己的?BaseHandler
?而不是RequestHandler。
請求處理程序可以通過?self.request
?訪問表示當(dāng)前請求的對象。有關(guān)屬性的完整列表,請參見HTTPServerRequest的類定義。
HTML表單使用的格式的請求數(shù)據(jù)將被解析,并通過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表單編碼對于參數(shù)是單個值還是包含一個元素的列表是不明確的,RequestHandler有不同的方法來允許應(yīng)用程序指示它是否需要列表。對于列表,請使用get_query_arguments和get_body_arguments,而不是它們的單數(shù)對應(yīng)項。
通過表單上傳的文件在?self.request.files
?中可用,它將名稱(HTML ?<input type="file">
?元素的名稱)映射到文件列表。每個文件都是?{"filename":...,"content_type":...,"body":...}
?格式的字典。?files
?對象僅在使用表單包裝器(即?multipart/form-data
?內(nèi)容類型)上載文件時存在;如果未使用此格式,則?self.request.body
?中可獲得原始上傳數(shù)據(jù)。默認情況下,上傳的文件在內(nèi)存中完全緩沖;如果需要處理太大而無法輕松保存在內(nèi)存中的文件,請參閱stream_request_body類裝飾器。
在demos目錄中,file_receiver.py顯示了接收文件上傳的兩種方法。
由于HTML表單編碼的特殊性(例如,單數(shù)和復(fù)數(shù)參數(shù)之間的模糊性),Tornado不嘗試將表單參數(shù)與其他類型的輸入統(tǒng)一起來。特別是,我們不解析JSON請求體。希望使用JSON而不是表單編碼的應(yīng)用程序可能會重寫prepare來解析其請求:
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è)計為在必要時被子類重寫。每次請求時,都會進行以下順序的調(diào)用:
initialize
?通常應(yīng)該只保存?zhèn)鬟f給成員變量的參數(shù);它可能不會產(chǎn)生任何輸出或調(diào)用方法,例如 send_errorprepare
?。?prepare
?可以產(chǎn)生輸出;如果它調(diào)用finish或?redirect
?等等方法,處理將在此停止get()
?、?post()
?、?put()
?等等。如果URL正則表達式包含捕獲組,則將它們作為參數(shù)傳遞給此方法get()
?或另一個 HTTP 方法返回之后。RequestHandler文件中記錄了所有設(shè)計為覆蓋的方法。一些最常用的重寫方法包括:
Server
?表頭)如果處理程序引發(fā)異常,Tornado將調(diào)用RequestHandler.write_error生成錯誤頁面。tornado.web.HTTPError可用于生成指定的狀態(tài)代碼;所有其他異常都返回500狀態(tài)。
默認錯誤頁面包括調(diào)試模式下的堆棧跟蹤和錯誤的單行描述(例如“500:內(nèi)部服務(wù)器錯誤”)。要生成自定義錯誤頁,請重寫RequestHandler.write_error(可能在所有處理程序共享的基類中)。這種方法通??梢酝ㄟ^write和render等方法產(chǎn)生輸出。如果錯誤是由異常引起的,則?exc_info
?將作為關(guān)鍵字參數(shù)傳遞(請注意,此異常不能保證是sys.exc_info中的當(dāng)前異常,因此?write_error
?必須使用例如traceback.format_exception而不是traceback.format_exc)
也可以從常規(guī)處理程序方法生成錯誤頁面,而不是?write_error
?通過調(diào)用 set_status、編寫響應(yīng)和返回。在簡單返回不方便的情況下,tornado.web.Finish可能會引發(fā)特殊異常以終止處理程序而不調(diào)用?write_error
?
對于404錯誤,使用?default_handler_class
?應(yīng)用程序設(shè)置。這個處理程序應(yīng)該覆蓋prepare,而不是像???get()??
?這樣更具體的方法,這樣它就可以與任何HTTP方法一起工作。它應(yīng)該如上所述生成錯誤頁面:通過引發(fā)?HTTPError(404)
?并覆蓋?write_error
?,或者調(diào)用?self.set_status(404)
?并直接在?prepare()
?中生成響應(yīng)。
在Tornado中,有兩種主要的重定向請求的方法:RequestHandler.redirect和RedirectHandler
可以在?self.redirect()
?方法中使用RequestHandler將用戶重定向到其他地方。還有一個可選參數(shù)?permanent
?,可用于指示重定向被視為永久性的。?permanent
?的默認值為?False
?,這將生成一個?302 Found
?的HTTP響應(yīng)代碼,適用于在成功的?POST
?請求后重定向用戶。如果?permanent
?為?True
?,則使用?301 Moved permanually
?HTTP響應(yīng)代碼,這有助于以SEO友好的方式重定向到頁面的規(guī)范URL
RedirectHandler允許您直接在Application路由表中配置重定向。例如,要配置單個靜態(tài)重定向:
app = tornado.web.Application([
url(r"/app", tornado.web.RedirectHandler,
dict(url="http://itunes.apple.com/my-app-id")),
])
RedirectHandler還支持正則表達式替換。以下規(guī)則將所有以?/pictures
?開頭的請求重定向到前綴?/photos
?:
app = tornado.web.Application([
url(r"/photos/(.*)", MyPhotoHandler),
url(r"/pictures/(.*)", tornado.web.RedirectHandler,
dict(url=r"/photos/{0}")),
])
與RequestHandler.redirect不同,RedirectHandler默認使用永久重定向。這是因為路由表在運行時不會更改,并且被認為是永久的,而在處理程序中找到的重定向可能是其他可能更改的邏輯的結(jié)果。要使用RedirectHandler發(fā)送臨時重定向,請在RedirectHandler初始化參數(shù)中添加?permanent=False
?
某些處理程序方法(包括?prepare()
?和HTTP的?get()
?/?post()
?方法等)可能會被重寫為協(xié)同路由,以使處理程序異步。
例如,下面是一個使用協(xié)同程序的簡單處理程序:
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")
更多建議: