您好,登錄后才能下訂單哦!
?
?
目錄
ver1:... 1
ver2,路由字典實現... 2
ver3,將路由功能封裝成類:... 4
ver4,404處理,webob.exc異常:... 5
ver5,注冊函數改造:... 7
路由正則匹配:... 10
?
?
?
?
web框架開發:
route路由:
簡單說,就是路怎么走,按不同的路徑分發數據;
url就是不同資源的路徑,不同的路徑應對應不同的應用程序來處理;
所以,代碼中應增加對路徑的分析處理;
?
不管是靜態web服務器,還是動態web服務器,都需要路徑和資源(或處理程序)的映射,最終返回html的文本;
靜態web server,解決路徑和文件之間的映射;
動態web server,解決路徑和應用程序之間的映射;
所有的web框架都是如此,都有路徑配置;
?
?
路由功能實現:
例:
增加路由:
/?? #返回歡迎內容
/python?? #返回hello python
其它?? #404
?
?
例:
@dec.wsgify
def app(request):
??? res = Response()
??? if request.path == '/':
??????? res.body = '<h2>welcome</h2>'.encode()
??? elif request.path == '/python':
??????? res.body = '<h2>hello python</h2>'.encode()
??? else:
??????? res.status_code = 404
??????? res.body = 'Not Found'.encode()
??? return res
?
?
?
例:
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
def notfound(request):
??? res = Response()
??? res.body = '<h2>Not Found</h2>'.encode()
??? return res
?
@dec.wsgify
def app(request):
??? if request.path == '/':
??????? return index(request)
??? elif request.path == '/python':
??????? return showpython(request)
??? else:
??????? return notfound(request)
?
例:
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
def notfound(request):
??? res = Response()
??? res.body = '<h2>Not Found</h2>'.encode()
??? return res
?
route_table = {
??? '/': index,
??? '/python': showpython
}
?
@dec.wsgify
def app(request):
??? return route_table.get(request.path, notfound)(request)
?
例:
增加注冊功能;
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
def notfound(request):
??? res = Response()
??? res.body = '<h2>Not Found</h2>'.encode()
??? return res
?
route_table = {}
?
def register(path, handler):
??? route_table[path] = handler
???
register('/', index)
register('/python', showpython)
?
@dec.wsgify
def app(request):
??? return route_table.get(request.path, notfound)(request)
?
?
思考如何把哪些函數放到外面;
好處,封裝在類里的,隨著類中代碼越來越多,方便之后移走,模塊化;
?
例:
from webob import Request, Response, dec
from wsgiref.simple_server import make_server
?
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
class Application:
??? def notfound(self, request):
??????? res = Response()
??????? res.body = '<h2>Not Found</h2>'.encode()
??????? return res
?
??? ROUTE_TABLE = {}?? #類屬性
?
??? @classmethod?? #類方法和普通方法都可,最好用類方法
??? def register(cls, path, handler):
??????? cls.ROUTE_TABLE[path] = handler
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? return self.ROUTE_TABLE.get(request.path, self.notfound)(request)
?
Application.register('/', index)
Application.register('/python', showpython)
?
if __name__ == '__main__':
??? ip = '127.0.0.1'
??? port = 9999
??? app = Application()
??? # app.register('/', index)?? #實例也可注冊,但這樣不好
??? # app.register('/python', showpython)
??? server = make_server(ip, port, app)
??? try:
??????? server.serve_forever()
??? except KeyboardInterrupt:
??????? pass
??? finally:
??????? server.shutdown()
??????? server.server_close()
?
?
查看源碼:
class HTTPNotFound(HTTPClientError):?? #繼承順序HTTPClientError-->HTTPError-->WSGIHTTPException-->Response
??? code = 404
??? title = 'Not Found'
??? explanation = ('The resource could not be found.')
?
注:
code、title、explanation,頁面展示先是這三個,再是自定義的body內容;
若要覆蓋body,要在Response的__init__()中設置;
class Response(object):
??? def __init__(self, body=None, status=None, headerlist=None, app_iter=None,
???????????????? content_type=None, conditional_response=None, charset=_marker,
???????????????? **kw):
?
例:
class Application:
??? # def notfound(self, request):
??? #???? res = Response()
??? #???? res.body = '<h2>Not Found</h2>'.encode()
??? #???? return res
?
??? ROUTE_TABLE = {}
?
??? @classmethod
??? def register(cls, path, handler):
??????? cls.ROUTE_TABLE[path] = handler
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? try:
??????????? return self.ROUTE_TABLE[request.path](request)
??????? except:
??????????? # return self.notfound(request)
??????????? raise exc.HTTPNotFound('您訪問的頁面被外星人劫持了')?? #所有異常都拋404,即便是內部定義的函數有問題也這樣,沒必要拋5XX之類的錯誤,防止別人拿到相關信息反推服務器版本之類的,b端不能看到服務器這邊的異常
?
例:
class MyHTTPNotFound(exc.HTTPNotFound):
??? code = 404
??? title = 'nimei'
??? explanation = 'nimeide'
?
class Application:
??? # def notfound(self, request):
??? #???? res = Response()
??? #???? res.body = '<h2>Not Found</h2>'.encode()
??? #???? return res
?
??? ROUTE_TABLE = {}
?
??? @classmethod
??? def register(cls, path, handler):
??????? cls.ROUTE_TABLE[path] = handler
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? try:
????? ??????return self.ROUTE_TABLE[request.path](request)
??????? except:
??????????? # return self.notfound(request)
??????????? # raise exc.MyHTTPNotFound('您訪問的頁面被外星人劫持了')
??????????? raise MyHTTPNotFound()
?
?
到此步,一個框架的雛形基本完成;
Application()是wsgi app,這個應用程序已變成了一個路由程序,處理邏輯已移到外面,外面的這部分就是留給程序員要完成的;
?
例:
from webob import Request, Response, dec, exc
from wsgiref.simple_server import make_server
?
class MyHTTPNotFound(exc.HTTPNotFound):
??? code = 404
??? title = 'nimei'
??? explanation = 'nimeide'
?
class Application:
?
??? ROUTE_TABLE = {}
?
??? @classmethod
??? def register(cls, path):
??????? def wrapper(handler):
??????????? cls.ROUTE_TABLE[path] = handler
??????????? return handler
??????? return wrapper
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? try:
??????????? return self.ROUTE_TABLE[request.path](request)
??????? except:
??????????? # raise exc.MyHTTPNotFound('您訪問的頁面被外星人劫持了')
??????????? raise MyHTTPNotFound()
?
# Application.register('/', index)
# Application.register('/python', showpython)
?
@Application.register('/')
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
@Application.register('/python')
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
if __name__ == '__main__':
??? ip = '127.0.0.1'
??? port = 9999
??? app = Application()
??? # app.register('/', index)
??? # app.register('/python', showpython)
??? server = make_server(ip, port, app)
??? try:
??????? server.serve_forever()
??? except KeyboardInterrupt:
??????? pass
??? finally:
??????? server.shutdown()
??????? server.server_close()
?
?
例,簡潔代碼:
from wsgiref.simple_server import make_server
from webob import Request, Response, dec, exc
?
class Application:
??? ROUTE_TABLE = {}
?
??? @classmethod
??? def register(cls, path):
??????? def wrapper(handler):
??????????? cls.ROUTE_TABLE[path] = handler
??????????? return handler
??????? return wrapper
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? try:
??????????? return self.ROUTE_TABLE[request.path](request)
??????? except:
??????????? raise exc.HTTPNotFound()
?
@Application.register('/')
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
@Application.register('/python')
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
if __name__ == '__main__':
??? ip = '127.0.0.1'
??? port = 9999
??? server = make_server(ip, port, Application())
??? try:
??????? server.serve_forever()
??? except:
??????? pass
??? finally:
??????? server.shutdown()
??????? server.server_close()
?
?
以上的路由實現,非常死板,用re改造;
注冊的時候,存入不再是路徑字符串,而是pattern;
__call__()實現模式和傳入路徑的比較;
?
注:
httpd編譯安裝前要裝pcre;
nginx自身已打包好相關的正則,所以不依賴第三方庫;
?
regex=re.compile(r'PATTERN')?? #編譯正則表達式;url只一行單選模式即可
regex.match(STRING)?? #必須從頭開始匹配,只匹配一次
regex.search(STRING)?? #只匹配一次
regex.fullmatch(STRING)?? #完全匹配
regex.findall(STRING)?? #從頭開始找,找到所有匹配
?
py中分組捕獲:
/(?P<biz>.*)/(?P<url>.*)?? #貪婪
/(?P<biz>.*?)/(?P<url>.*?)?? #非貪婪
?
例:
@Application.register('/python$')?? #只匹配/python
@Application.register('^/$')?? #只匹配根,放最后匹配
?
例:
from wsgiref.simple_server import make_server
from webob import Request, Response, dec, exc
import re
?
class Application:
??? # ROUTE_TABLE = {}
??? ROUTE_TABLE = []?? #[(re.compile(pattern), handler)],二元組列表;此處用列表或有序字典;用dict不合適,key是路徑模式,不能保證其順序,匹配的時候應是有序的
?
??? @classmethod
??? def register(cls, pattern):
??????? def wrapper(handler):
??????????? cls.ROUTE_TABLE.append((re.compile(pattern), handler))?? #注冊的時候編譯正則表達式
??????????? return handler
??????? return wrapper
?
??? @dec.wsgify
??? def __call__(self, request:Request) -> Response:
??????? for regex, handler in self.ROUTE_TABLE:
???? ???????matcher = regex.search(request.path)?? #match()、search()均可
??????????? if matcher:
??????????????? return handler(request)
??????? raise exc.HTTPNotFound()
?
@Application.register('^/python$')?? #有匹配的順序,根放到最后;showpython=Application.register('^/python$')(showpython)
def showpython(request):
??? res = Response()
??? res.body = '<h2>hello python</h2>'.encode()
??? return res
?
@Application.register('^/$')
def index(request):
??? res = Response()
??? res.body = '<h2>welcome</h2>'.encode()
??? return res
?
if __name__ == '__main__':
??? ip = '127.0.0.1'
??? port = 9999
??? server = make_server(ip, port, Application())
??? try:
??????? server.serve_forever()
??? except:
??????? pass
??? finally:
??????? server.shutdown()
??????? server.server_close()
?
?
?
?
?
?
?
?
?
?
?
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。