目录
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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。