tornado 学习笔记7 RequestHandler功能分析
轉(zhuǎn)載自廖飛的博客
?????? 在第5部分講到,構(gòu)建一個(gè)tornado網(wǎng)站,必須包含一個(gè)或者多個(gè)handler,這些handler是RequestHandler的子類。每個(gè)請求都會(huì)被映射到handler中進(jìn)行處理,處理后再將結(jié)果返回給客戶端。所以,可以看到hanlder作為客戶端請求跟業(yè)務(wù)服務(wù)邏輯間的橋梁,如果拿MVC的模式來類比的話,每個(gè)handler就相當(dāng)于MVC中的Controller。
?????? RequestHanlder作為所有hanlder的父類,我們看看他有哪些方法與接口,子類需要怎樣繼承?
?
7.1構(gòu)造函數(shù)
定義:
def __init__(self, application, request, **kwargs):參數(shù):
????? application: Application對象
????? request: request請求對象
?????? kwargs:其他參數(shù),在hanlder映射配置時(shí),可以設(shè)置。
處理過程:
super(RequestHandler, self).__init__()self.application = application self.request = request self._headers_written = False self._finished = False self._auto_finish = True self._transforms = None # will be set in _execute self._prepared_future = None self.path_args = None self.path_kwargs = None self.ui = ObjectDict((n, self._ui_method(m)) for n, m inapplication.ui_methods.items()) # UIModules are available as both `modules` and `_tt_modules` in the # template namespace. Historically only `modules` was available # but could be clobbered by user additions to the namespace. # The template {% module %} directive looks in `_tt_modules` to avoid # possible conflicts. self.ui["_tt_modules"] = _UIModuleNamespace(self,application.ui_modules) self.ui["modules"] = self.ui["_tt_modules"] self.clear() self.request.connection.set_close_callback(self.on_connection_close) self.initialize(**kwargs)?? 5.??? 調(diào)用初始化函數(shù)。
self.initialize(**kwargs)?????? 這個(gè)被子類繼承,針對每個(gè)hanlder實(shí)現(xiàn)自己的初始化過程。
?
入點(diǎn)函數(shù)
7.2 initialize方法
????? 該方法被子類重寫,實(shí)現(xiàn)初始化過程。參數(shù)的來源于配置Application時(shí),傳遞的參數(shù)。舉例如下:
# -*- coding: utf-8 -*- from tornado.ioloop import IOLoop from tornado.web import Application, RequestHandler__author__ = 'Administrator'class BookRequestHandler(RequestHandler):def initialize(self, welcome):self.welcome = welcomedef get(self, *args, **kwargs):print(self.welcome)self.write(self.welcome)welcome = "**大學(xué)圖書館" app = Application(handlers=[(r"/book", BookRequestHandler, dict(welcome=welcome)), ])def main():app.listen(8888)IOLoop.current().start()if __name__ == "__main__":main() ?????????????????? 將welcome初始化的值傳遞到BookRequestHandler的self.welcome屬性中。當(dāng)訪問http://localhost:8888/book時(shí),打印出welcome的值。
????????? 結(jié)果如下圖:
7.3 prepare 、 on_finish方法
????????? prepare方法用于當(dāng)真正調(diào)用請求處理方法之前的初始化處理,比如get、post方法。而on_finish用于請求處理結(jié)束后的一些清理工作。這兩個(gè)方法一個(gè)在處理前,一個(gè)在處理后,可以根據(jù)實(shí)際需要進(jìn)行重寫。比如用prepare方法做些初始化操作(比如賦值設(shè)置全局變量,比如打開I/O),而on_finish方法可以做一些清理對象占用的內(nèi)存或者關(guān)閉數(shù)據(jù)庫連接等等。舉個(gè)例子,來證明他們的執(zhí)行順序。
class BookRequestHandler(RequestHandler):def initialize(self, welcome,value2):print("initialize method:initilize some variables....")self.welcome = welcomeself.value2=value2def get(self, *args, **kwargs):#print(self.welcome + "\r\n" + "and value2 =" + self.value2)print("get method: Processing get Method...........")self.write(self.welcome + "\r\n" + "and value2 =" + self.value2)def set_default_headers(self):self._headers.add("custom_header1", "custom_header1")self._headers.add("custom_header2", "custom_header2")def prepare(self):print("prepare method:initilize some variables....")def on_finish(self):print("on_finish method:clear some memory or close database connection")????? 執(zhí)行的結(jié)果如下:
?????? 所以得出執(zhí)行的順序?yàn)?#xff1a;
?????? initialize > prepare > get > on_finish
?????? 如果有熟悉Java 的JUnit的話呢,prepare跟on_finish方法相當(dāng)于before跟behind兩個(gè)注解的功能。
獲得輸入的函數(shù):
7.4? get_argument、get_arguments方法
??????? 返回給定參數(shù)的值,get_argument獲得單個(gè)值,而get_arguments是針對參數(shù)存在多個(gè)值得情況下使用,返回多個(gè)值的列表。看一get_arguments方法的源代碼,如下:
????????? 它的實(shí)現(xiàn)是調(diào)用了內(nèi)部方法_get_arguments,注意傳遞的參數(shù)self.request.arguments,從request(HTTPServerRequest對象)的arguments屬性中去查詢給定名稱的值。看看HTTPServerRequest源代碼(位于tornado>httputil.py)對arguments的解釋,如下截圖:
????????? 大體意思就是說,這里存儲(chǔ)的是客戶端GET/POST方法提交上來的合并后的參數(shù)列表集合。也就是說RequestHanlder的get_arguments方法是能獲得不管是Get還是POST得參數(shù)的值。舉個(gè)GET提交參數(shù)的例子,
????????? 修改BookRequestHanlder的get方法。如下:
def get(self, *args, **kwargs):#print(self.welcome + "\r\n" + "and value2 =" + self.value2)print("get method: Processing get Method...........")#self.write(self.welcome + "\r\n" + "and value2 =" + self.value2)self.write("參數(shù)name的值為:" + self.get_argument("name", "liaofei"))?????? 向游覽器中打印出參數(shù)name的值,游覽器中訪問:http://localhost:8888/book?name=brain,結(jié)果如下圖所示:
????????? 在舉個(gè)POST方式提交參數(shù)的例子,在BookRequestHanlder 中新增POST方法,如下:
def post(self, *args, **kwargs):print(self.request.arguments)print("POS age:" + self.get_argument("age"))self.write("POS age:" + self.get_argument("age"))??????? 網(wǎng)上下載一個(gè)模擬工具進(jìn)行POST數(shù)據(jù)提交,我找了很久用了,找到如下工具(很多工具不能用,這個(gè)稍微能用一下),
????????? 后臺(tái)打印的結(jié)果為:,HTTPRequest 的arguments屬性是一個(gè)字典。
???????? 提一個(gè)問題?如果URL中帶有age查詢參數(shù),而post過去也有age參數(shù),這時(shí)HTTPRequest 的arguments中age的值會(huì)是什么???測試一下便知。按照如下訪問,
??????? 后臺(tái)打印的結(jié)果為:,age的值是一個(gè)列表集合,將POST提交方式age參數(shù)值跟GET提交方式age參數(shù)值合并啦,而且是GET在前,POST再后。而get_arguments獲得最后一個(gè)。
7.5 get_query_argument、get_query_arguments方法
?????? 與get_argument、get_arguments功能類似,只是他僅僅是從URL查詢參數(shù)中獲取值。
7.6? get_body_argument、get_body_arguments方法
????? 與get_argument、get_arguments功能類似,只是他僅僅是從body中獲取值。
?? 再提一個(gè)問題?????get_query_argument、get _argument、get_body_argument的區(qū)別????測試一下便知。
?? 按如下修改post方法,
def post(self, *args, **kwargs):print(self.request.query_arguments)print(self.request.arguments)print(self.request.body_arguments)print("POS age:" + self.get_argument("age"))self.write("POS age:" + self.get_argument("age"))??????? 按如下方式模擬訪問:
?????????? 后臺(tái)打印的結(jié)果如下圖:
?????????? 所以得出結(jié)論就是,get _argument獲取的值范圍是get_query_argument與get_body_argument兩者范圍的合并。
輸出響應(yīng)函數(shù):
7.7 clear方法
????? 重置響應(yīng)的所有的頭部以及內(nèi)容。
"""Resets all headers and content for this response.""" self._headers = httputil.HTTPHeaders({"Server": "TornadoServer/%s" % tornado.version,"Content-Type": "text/html; charset=UTF-8","Date": httputil.format_timestamp(time.time()), }) self.set_default_headers() self._write_buffer = [] self._status_code = 200 self._reason = httputil.responses[200]????? 處理過程
7.9 set_default_headers方法
????? 上面說了set_default_headers 方法是實(shí)現(xiàn)請求響應(yīng)頭部的自定義實(shí)現(xiàn),被子類重寫。舉個(gè)例子。
?????? 在上面的BookRequestHandler中加入以下代碼
def set_default_headers(self):self._headers.add("custom_header1", "custom_header1")self._headers.add("custom_header2", "custom_header2")?????? 通過游覽器訪問http://localhost:8888/book,用firebug查詢響應(yīng)頭。結(jié)果如下:
7.10 write方法
??????? 將給定的塊輸出到輸出緩存中。如果給定的塊是一個(gè)字典,就會(huì)將這個(gè)快當(dāng)成是JSON并且將Content_Type設(shè)置成application/json返回給客戶端。但是,如果你想用不同的Content_Type發(fā)送JSON,可以在調(diào)用write方法后再調(diào)用set_header方法進(jìn)行設(shè)置。
?????? 注意,list 列表集合是不會(huì)轉(zhuǎn)化成JSON的,原因是考慮到跨域的安全。所有的JSON輸出都必須用字典包裝。具體源碼說明如下:
7.11 rend 方法
??????? 用給定的參數(shù)渲染模板。這個(gè)涉及到模板的概念,后續(xù)再學(xué)。
7.12? write_error方法
??????? 重寫自定義錯(cuò)誤頁面的實(shí)現(xiàn)。
??????? 如果error是由沒有捕獲的異常(包括HTTPError)引起的,通過kwargs[|”exc_info”]能獲取exc_info元組。實(shí)現(xiàn)代碼如下:
??????????? 舉個(gè)例子實(shí)現(xiàn)一個(gè)自定義的錯(cuò)誤頁面,在BookRequestHandler中添加如下代碼:
def write_error(self, status_code, **kwargs):self.write("oh,my god!出錯(cuò)啦!!!!請聯(lián)系系統(tǒng)管理員。\n")self.write("呵呵,也沒關(guān)系,我已經(jīng)講錯(cuò)誤信息記錄在日志中去了,系統(tǒng)管理員會(huì)看到的。\r\n")if "exc_info" in kwargs:self.write("錯(cuò)誤信息為:\r\n")for line in traceback.format_exception(*kwargs["exc_info"]):self.write(line)self.finish()并將get方法修改成:
def get(self, *args, **kwargs):# print(self.welcome + "\r\n" + "and value2 =" + self.value2)print("get method: Processing get Method...........")# self.write(self.welcome + "\r\n" + "and value2 =" + self.value2)# print(self.request.query_arguments)# print(self.request.arguments)# print(self.request.body_arguments)# self.write("參數(shù)name的值為:" + self.get_argument("name", "liaofei"))print(1/0) ??????????????? print(1/0)語句,人為地制造一個(gè)錯(cuò)誤。在游覽器中訪問http://localhost:8888/book,得到如下結(jié)果,
??????????? 就是使用了重寫write_error中的方法實(shí)現(xiàn)。
Cookie相關(guān)函數(shù)
7.13 get_cookie、set_cookie
????? 獲取與設(shè)置cookie的值。這個(gè)對熟悉web開發(fā)的人,一看就明白。就不多解釋。
7.14 get_secure_cookie、set_secure_cookie
??????? 獲取與設(shè)置安全cookie的值。與7.13 相比加了一個(gè)單詞secure(安全),就說明是為cookie安全加密解密的作用。這個(gè)方法涉及到cookie_secret 的Application 設(shè)置選項(xiàng)。來舉個(gè)列子說明他們之間的區(qū)別:
加入以下代碼:
class CookieRequestHandler(RequestHandler):def get(self, flag):if flag == '0':self.set_cookie("user", "liaofei")elif flag == '1':userCookie = self.get_cookie("user")self.write(userCookie)????? 修改application的配置
settings = {"debug":False,"cookie_secret":"gagagaarwrslijwlrjoiajfoajgojowurwojrowjojgfoaguuuu9", }app = Application(handlers=[(r"/book", BookRequestHandler, dict(welcome=welcome, value2=value2)),(r"/cookie/([0-1]+)", CookieRequestHandler), ], **settings)(r"/cookie/([0-1]+)", CookieRequestHandler), ], **settings) ???????????? 注意settings中設(shè)置了cookie_secret的值。
?????? 訪問http://localhost:8888/cookie/0時(shí),調(diào)用set_cookie設(shè)置cookie中user的值為liaofei,并調(diào)用set_secure_cookie設(shè)置cookie 中usersecure的值同樣為liaofei。用firebug查看這個(gè)相同值得cookie(都是liaofei),發(fā)現(xiàn)在游覽器客戶端的值是不一樣的,一個(gè)加密過,一個(gè)未加密。具體結(jié)果如下圖:
分類: Python Tornado 好文要頂 關(guān)注我 收藏該文 廖飛關(guān)注 - 3
粉絲 - 11 +加關(guān)注 0 0 ? 上一篇:tornado 學(xué)習(xí)筆記6 Application 源碼分析
? 下一篇:tornado 學(xué)習(xí)筆記8 模板以及UI
posted @ 2015-11-05 11:48 廖飛 閱讀(2934) 評論(0) 編輯 收藏
轉(zhuǎn)載于:https://www.cnblogs.com/silence-cc/p/10010024.html
總結(jié)
以上是生活随笔為你收集整理的tornado 学习笔记7 RequestHandler功能分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux中getchar函数用法,li
- 下一篇: 2022全球「高被引科学家」榜单出炉!中