目錄
前言
一、在Handler.on_finish部分記錄每次接口請求的路徑、時間、耗時,輸出日志。
二、重寫Handler中的get和post方法,實現請求能夠分發到Handler的不同處理函數。
還沒有接觸過Tornado框架的可以看這章:
實習手冊二(基於Tornado框架的接口響應服務)
沒有學習過框架的同學可以先看看下面這個視頻教程:
tornado快速入門教程
以及網頁教程:
酷python-tornado基礎教程
本章我們要在Tornado框架中實現兩個功能:
一、在Handler.on_finish部分記錄每次接口請求的路徑、時間、耗時,輸出日志。
二、重寫Handler中的get和post方法,實現請求能夠分發到Handler的不同處理函數。
1、首先,Handler.on_finish部分是什麼?
我們訪問網頁時的請求都是通過請求處理器來對我們的請求進行處理,從而返回對應的操作,在Tornado框架中,我們通過不同路由來響應不同的請求,不同請求有著對應的處理器(Handler)來對它們進行處理,這些處理器都繼承同一個父類:Tornado.web中的RequsetHandler類。我們通過command+鼠標左鍵點擊,即可查看RequestHandler中的對應方法。
其中,我們可以看到get,post,on_finish方法等。
根據英文提示,我們可以看到在on_finish方法裡,提示我們可以通過重寫此方法來進行進程的清空,日志的記錄和輸出等。
關於日志(logging),沒有學習過的小伙伴可以看這篇:
python + logging 實現日志輸出及保存到文件
要在Handler中實現日志的輸出與打印,我們可以用到python自帶的logging包,用import logging命令即可調用。
# 調用tornado庫
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
import logging
# Hello處理器
class HelloHandler(RequestHandler):
# 日志方法
def log(self,msg): # msg為日志輸出的信息
logger = logging.getLogger('logger')
logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
# 規定日志保存的路徑
file_handler = logging.FileHandler('../test2/logs/log.txt')
file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info(msg)
# get方法重寫
def get(self):
self.write("Hello,world")
# on_finish方法重寫
def on_finish(self):
# 獲取請求路徑,請求方法,請求頭,拼接成字符串,傳入log方法,作為日志所保存的內容
msg = str(self.request.path) + str(self.request.method) + str(self.request.headers)
# 調用log方法
self.log(msg)
# 路由設置
app = Application([
(r"/", HelloHandler),
])
# 程序啟動
if __name__ == "__main__":
# 設置端口號
app.listen(8888)
IOLoop.current().start()
然後再次在浏覽器中輸入網址來測試我們的代碼是否成功實現日志功能,可以看到,在控制台中已經輸出了我們的日志信息:
然後打開我們logs文件夾中的log.txt,也可以查看到我們的日志信息:
注意,在運行文件時,首先要確保是否存在對應的文件夾來讓日志進行保存,沒有的話需要創建,不然運行時會報錯。
上面介紹過我們可以通過command+鼠標左鍵來查看類或者方法,可以看到Tornado.web的RequestHandler類中存在get和post方法,下面先簡單介紹一下它們:
get和post可以理解成傳遞請求參數的不同方法,get傳遞的參數一般是用於查詢的參數,get請求的數據會附在URL之後,以?分割URL和傳輸數據,參數之間以&相連,並且get的長度受限於url的長度,而url的長度限制是特定的浏覽器和服務器設置的,理論上get的長度可以無限長。
post把提交的數據則放置在是HTTP包的包體中,post是沒有大小限制的,HTTP協議規范也沒有進行大小限制,起限制作用的是服務器的處理程序的處理能力,post一般處理私密性的信息,如登陸賬戶,修改密碼等私密性操作。
要實現用get和post請求來實現請求能夠分發到Handler的不同處理函數,這裡就牽扯到怎麼實現接口的調用了,那麼,什麼是接口呢?
接口是一種用來定義程序的協議,描述可屬於任何類或結構的一組相關行為
按理解來說,接口是後端處理數據然後返回的一個連接處,接著前端可以通過這個接口拿到後端的數據。在Handler中,我們可以把接口理解成一種處理請求的方法,不同的接口對應著不同的請求處理方法。
首先,想要實現請求的分發,就需要在get和post方法中對用戶訪問的路徑進行處理,獲取請求路徑的方法在上個任務中已經有所提及(request.path)
此外,這裡還得介紹一下Tornado.web中的Application類其中的路由參數。不同的路由決定不同的大功能,而每個大功能中又有各自的小功能,舉個例子,比如用戶的注冊,查詢,修改是三個大功能,而修改中有著修改密碼,修改頭像這些小功能,路由就是用來實現大功能的不同請求路徑,而get和post分發來實現不同的小功能的分發。
根據代碼來理解會更加的清晰:
路由設置的代碼(示例):
app = Application([
(r'/user/register/.*', RegisterHandler),
(r'/user/search/.*', SearchHandler),
(r'/user/change/.*', ChangeHandler)
])
其中Application中的一條數據就代表了一個大的功能,其中,
'/user/change/.*'
代表了功能的請求路徑,後面的(.*)是正則表達式的用法,你可以把它理解成後面會跟接著對應的小功能的路徑如:
'/user/change/change_pwd'或者'/user/change/change_username'
所以,可以這麼理解,功能的分發就取決於請求路徑的最後一段,當然也有別的情況,只需要設計不同的邏輯進行處理即可。
因此,在get和post請求中,我們需要對請求的路徑進行處理,來找到用於分發的字段,從而調用對應的接口方法進行處理。
# 調用tornado庫
from tornado.web import RequestHandler, Application
from tornado.ioloop import IOLoop
import logging
# Meet處理器
class MeetHandler(RequestHandler):
# 日志方法
def log(self,msg): # msg為日志輸出的信息
logger = logging.getLogger('logger')
logger.setLevel(level=logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s')
# 規定日志保存的路徑
file_handler = logging.FileHandler('../test2/logs/log.txt')
file_handler.setLevel(level=logging.INFO)
file_handler.setFormatter(formatter)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.DEBUG)
stream_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
logger.info(msg)
# get方法重寫
def get(self):
# 將路徑以'/'來劃分,組合成一個列表
path = self.request.path.split('/')
# 調用對應的接口方法是根據path列表中的最後一個字段
method = path[-1]
# 使用callable函數判斷方法是否能夠調用,getattr函數用來判斷方法能否調用到
if callable(getattr(self, method)):
getattr(self, method)()
else:
self.write("404 not found")
# hello接口
def hello(self):
self.write("Hello, world")
# goodbye接口
def goodbye(self):
self.write("Goodbye, world")
# on_finish方法重寫
def on_finish(self):
# 獲取請求路徑,請求方法,請求頭,拼接成字符串,傳入log方法,作為日志所保存的內容
msg = str(self.request.path) + str(self.request.method) + str(self.request.headers)
# 調用log方法
self.log(msg)
# 路由設置
app = Application([
(r"/meet/.*", MeetHandler)
])
# 程序啟動
if __name__ == "__main__":
# 設置端口號
app.listen(8888)
IOLoop.current().start()
可以看到,我們在MeetHandler中寫了hello和goodbye兩個簡單的接口,現在我們再次訪問服務界面
訪問http://127.0.0.1:8888/meet/hello
訪問http://127.0.0.1:8888/meet/goodbye
這樣便實現了請求的分發。