路由的基本概念:html
根據不一樣的訪問路徑調用不一樣的方法或者類python
from webob import Response,Request,dec from wsgiref.simple_server import make_server,demo_app def index(request:Request): res = Response() res.body = 'index.html'.encode() return res def showpython(request:Request): res = Response() res.body = 'show_python'.encode() return res def notfound(): res = Response() res.status_code = 404 return res @dec.wsgify def app(request:Request): if request.path == '/': return index(request) elif request.path == '/python': return showpython(request) else: return notfound()
若是用字典描述它是否更好web
若是找不到則調用notfound 後端
@dec.wsgify def app(request:Request): ROUTE.get(request.path,notfound)(request) if __name__ == "__main__": ip = '127.0.0.1' port = 9999 server = make_server(ip,port,app) server.serve_forever() server.server_close()
實現註冊app
這樣的話就能夠將路由表設置爲空框架
用這個路由的話起碼保證了已經註冊過了ide
def index(reques:Request): res = Response() res.body = 'index.html'.encode() return res def showpython(reques:Request): res = Response() res.body = 'python.html'.encode() return res def notfound(): res = Response() res.status_code = 404 res.body = 'Not Found'.encode() return res # Route_Table ROUTERTABLE = {} def register(path,handler): ROUTERTABLE[path] = handler register('/',index) register('/python',showpython) @wsgify def app(request:Request): ROUTE.get(request.path, notfound)(request)
路由的封裝
函數
class APP: def index(self,request:Request): res = Response() res.body = 'hello'.encode() return res def showpython(self,request:Request): res = Response() res.body = 'show python'.encode() return res
分析好處與瓶頸分別在哪裏this
對一個web框架來說,這些方法都應該是用戶本身去定義,而並不是是框架內去完成的,由於框架是提供用戶去使用,因此是由使用者去實現spa
那麼對於對於哪些是放在外面,合理的規劃以下:
class APPlication: def __init__(self,env,start_response): pass def notfound(request:Request): res = Response res.status_code = 404 res.body = '404'.encode() return res #路由表 ROUTERTABLE = {} def register(path,handler): ROUTERTAB[path] = handler @dec.wsgify def app(request:Request): return ROUTETABLE.get(request.path,notfound)(request) #在外部定義執行的函數 def index(self,request:Request): res = Response() res.body = 'hello'.encode() return res
類的實例化
若是經過類進行定義那麼必須實例化,由於須要__init__的支撐
對於一個類中要麼在init中實現,要麼在__call__ 中實現
__init__:若是定義在init中,實例化後則是被寫死,顯然不符當前調用的靈活性,至關於在調用缺省的兩個函數
class APPlication: def __init__(self,env,start_response):
__call__:若是在__call__中定義,顯然調用和傳參是比較靈活的
思考一個問題:__call__是如何調用的
改進:
對於server來說
server = make_server(ip,port,app)
必定是看到兩個參數調用,由於有裝飾器被裝飾必定保證這個__call__ 必定被轉化成wsgify
class Application: def notfound(request:Request): res = Response() res.status_code = 404 res.body = 'not found~~'.encode() return res ROUTETABLE = {} # 註冊 def register(path,handler): ROUTETABLE[path] = handler @dec.wsgify def __call__(self,request:Request): return ROUTETABLE.get(request.path, notfound)(request) def index(request:Request): res = Response res.body = 'hh'.encode() return res
這樣的話經過裝飾器進行修飾以後,變成了咱們想要的方式
最開始的__call__方法必須知足兩個參數 request 和 response 必須保證進出,那若是經過wsgify的裝飾以後,那麼確保這個__call__變成了接口,知足了接口定義的要求
這裏request就是業務上的第一個參數
經過request傳進以後,返回一個返回值,能夠達到最後要求,只不過是用裝飾器來完成
返回值須要經過裝飾器 start_response 保證最後是一個可迭代對象
簡單的來說,就是將這個例子:
@wsgify
def myfunc(request:Request):
return Response('hey here')
轉爲了另外一個例子:
@wsgify
#def __call__(self, *args, **kwargs):
def __call__(self,request:Request):
return ROUTER.get(request.path, self.notfound)(request)
經過__call__ 方法能夠直接拿來作函數使用,這就省去了一些沒必要要的麻煩
添加異常,避免訪問出現問題
@dec.wsgify
def __call__(self,request:Request):
try:
print(request) #將request 傳遞給了index(request)
return cls.ROUTE[request.path](request)
except:
return self.notfound(request)
加入註冊
傾向於使用類方法,將註冊函數加入到類中
先到server中由其交給業務函數管理,業務函數是用戶根據本身的需求本身填寫內容
from webob import Response,Request,dec,exc from wsgiref.simple_server import make_server,demo_app import re class Application: def notfound(self,request:Request): res = Response() res.status_code = 404 res.body = 'hel'.encode() return res ROUTE = { } @classmethod def register(cls,path,handler): cls.ROUTE[path] = handler @dec.wsgify def __call__(self, request:Request): return self.ROUTE.get(request.path, self.notfound)(request) def index(request:Request): res = Response() res.status_code = 200 res.body = 'hhh'.encode() return res Application.register('/',index) if __name__ == "__main__": ip = '127.0.0.1' port = 9999 server = make_server(ip,port,Application()) server.serve_forever() server.server_close()
exc 異常模塊及狀態碼相關處理
exc主要提供了異常模塊及狀態碼相關的處理功能
導入模塊
from webob import Response,Request,dec,exc
查看源碼:
看到源碼內定義了幾乎全部的HTTP_Code 每一個都是經過單獨類來實現,並繼承自HTTPClientxxxx
好比:200的類
class HTTPOk(WSGIHTTPException): """ Base class for the 200's status code (successful responses) code: 200, title: OK """ code = 200 title = 'OK'
再好比404的類
class HTTPNotFound(HTTPClientError): """ subclass of :class:`~HTTPClientError` This indicates that the server did not find anything matching the Request-URI. code: 404, title: Not Found """ code = 404 title = 'Not Found' explanation = ('The resource could not be found.')
發現每一個狀態碼的類都是子類,繼續跟進父類查看:
查看HTTPClientError
class HTTPClientError(HTTPError): code = 400 title = 'Bad Request' explanation = ('The server could not comply with the request since\r\n' 'it is either malformed or otherwise incorrect.\r\n') 也是一個子類,再次跟進HTTPError class HTTPError(WSGIHTTPException): WSGIHTTPException 代碼以下 class WSGIHTTPException(Response, HTTPException): ## You should set in subclasses: # code = 200 # title = 'OK' # explanation = 'why this happens' # body_template_obj = Template('response template') code = 500 title = 'Internal Server Error' explanation = '' body_template_obj = Template('''\ ${explanation}<br /><br /> ${detail} ${html_comment} ''')
它的子類將其方法進行逐層覆蓋,並返回其實仍是調用的這個方法
並調用了wsgi的接口函數wsgi_response
最後實際調用的是__call__並傳遞兩個參數,environ 請求的全部信息 以及 start_response
所謂http code就是封裝一個編號並返回response body的內容
exc是多繼承,繼承了response,將一個缺省的body能夠傳遞
若是出現某些問題則調用異常,這個異常自己繼承resopnse進行raise出去
因此直接調用exc.類名就能夠了
@dec.wsgify def __call__(self,request:Request): try: print(request) return self.ROUTE[request.path](request) except: return exc.HTTPNotFound('hahaha')
因此,只要拋異常就是沒有正常獲取,直接拋異常便可
改進註冊過程,使用裝飾器進行包裝
咱們看到效果,當註冊路由的時候,使用Application.reg功能進行調用,可是明顯是不靈活的
可否像其餘框架直接在方法或者函數上面寫明要指定的路由路徑呢
好比
@xxxxx.register('/',index) def index(request:Response): res = Response() res.body = 'index'.encode() return res 目前來看,只能使用裝飾器來完成當前效果了 等價式:--> index = app.reg('/')(index) @dec.wsgify def __call__(self,request:Request): try: print(request) return self.ROUTE[request.path](request) # return self.ROUTE.get(request.path, self.notfound)(request) except: return exc.HTTPNotFound('hahaha') # @Application.reg('/',index) 帶參裝飾器 --> Application() --> func(path)(index) @Application.reg('/') def index(request:Response): res = Response() res.body = 'index'.encode() return res
路由主要是解決了後端問題
完整以下:
from webob import Response,Request,exc from webob.dec import wsgify from wsgiref.simple_server import make_server,demo_app import re # @wsgify # def index(request:Request): # res = Response() # res.body = 'index.html'.encode() # return res class Application: ROUTER_TABLE = {} @classmethod def register(cls,path): def wapper(handler): cls.ROUTER_TABLE[path] = handler print(cls.ROUTER_TABLE) return handler return wapper @wsgify def __call__(self, request): try: print(request.path) print(request) print(self.ROUTER_TABLE[request.path]) return self.ROUTER_TABLE[request.path](request) except: raise exc.HTTPNotFound('not funod~~') @Application.register('/') # --> index = app.reg('/')(index) def index(request:Request): res = Response() res.body = 'index.html'.encode() return res @Application.register('/python') # --> index = app.reg('/')(index) def showpython(request:Request): res = Response() res.body = 'python'.encode() return res if __name__ == "__main__": ip = '127.0.0.1' port = 9999 server = make_server(ip,port,Application()) server.serve_forever() server.server_close()