标签:
这一阵正在学习廖雪峰老师的实战课程,这里对其中web.py框架进行一些分析,总结一下学到的东西。
这一部分的课程网站:http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/0014023080708565bc89d6ab886481fb25a16cdc3b773f0000
近期学习了廖雪峰老师Python教程实战课程中WebApp博客的编写,这个项目最核心的部分就是web框架的编写。在这里总结一下学到的东西。
def get(path): def _decorator(func): func.__web_route__ = path func.__web_method__ = ‘GET‘ return func return _decorator def post(path): def _decorator(func): func.__web_route__ = path func.__web_method__ = ‘POST‘ return func return _decorator
1 def view(path): 2 3 def _decorator(func): 4 @functools.wraps(func) 5 def _wrapper(*args, **kw): 6 r = func(*args, **kw) #这时函数原本应该返回的值,应当为字典类型。 7 if isinstance(r, dict): 8 logging.info(‘return Template‘) 9 return Template(path, **r) #得到self.template_name 和 self.model。 10 raise ValueError(‘Expect return a dict when using @view() decorator.‘) 11 return _wrapper 12 return _decorator
def interceptor(pattern=‘/‘): def _decorator(func): #简单来说就是:给func添加了一个__interceptor__属性,这一属性并非一个单纯的值, # 而是一个可调用的函数,这个函数使用时: # func.__interceptor__(ctx.request.path_info) # 根据ctx.request.path_info判断返回True或者False,从而决定拦截函数是否运行-->看2. func.__interceptor__ = _build_pattern_fn(pattern) return func return _decorator
根据
ctx.request.path_info判断返回True或者False,从而决定拦截函数是否运行;def _build_interceptor_fn(func, next): def _wrapper(): if func.__interceptor__(ctx.request.path_info): #如果上面为True,那么启动拦截函数 return func(next) else: #否则直接运行原函数 return next() return _wrapper
1 class Route(object): 2 ‘‘‘ 3 A Route object is a callable object. 4 ‘‘‘ 5 def __init__(self, func): 6 self.path = func.__web_route__ 7 self.method = func.__web_method__ 8 self.is_static = _re_route.search(self.path) is None 9 if not self.is_static: 10 self.route = re.compile(_build_regex(self.path)) 11 self.func = func 12 def match(self, url): 13 m = self.route.match(url) 14 if m: 15 return m.groups() 16 return None 17 def __call__(self, *args): 18 return self.func(*args) 19 def __str__(self): 20 if self.is_static: 21 return ‘Route(static,%s,path=%s)‘ % (self.method, self.path) 22 return ‘Route(dynamic,%s,path=%s)‘ % (self.method, self.path) 23 __repr__ = __str__
1 class Request(object): 2 ‘‘‘ 3 Request object for obtaining all http request information. 4 ‘‘‘ 5 def __init__(self, environ): 6 self._environ = environ 7 def _parse_input(self): 8 def _convert(item): 9 if isinstance(item, list): 10 return [_to_unicode(i.value) for i in item] 11 if item.filename: 12 return MultipartFile(item) 13 return _to_unicode(item.value) 14 #将self._environ[‘wsgi.input‘]转换成字典类型 15 fs = cgi.FieldStorage(fp=self._environ[‘wsgi.input‘], environ=self._environ, keep_blank_values=True) 16 inputs = dict() 17 for key in fs: 18 inputs[key] = _convert(fs[key]) 19 return inputs 20 def _get_raw_input(self): 21 ‘‘‘ 22 Get raw input as dict containing values as unicode, list or MultipartFile. 23 ‘‘‘ 24 if not hasattr(self, ‘_raw_input‘): 25 #将上面的结果放到_raw_input属性中 26 self._raw_input = self._parse_input() 27 return self._raw_input 28 def input(self, **kw): 29 #复制上边得到的表单字典 30 copy = Dict(**kw) 31 raw = self._get_raw_input() 32 for k, v in raw.iteritems(): 33 copy[k] = v[0] if isinstance(v, list) else v 34 return copy 35 def get_body(self): 36 #得到environ[‘wsgi.input‘]原始的数据 37 fp = self._environ[‘wsgi.input‘] 38 return fp.read() 39 @property 40 def remote_addr(self): 41 return self._environ.get(‘REMOTE_ADDR‘, ‘0.0.0.0‘) 42 def _get_cookies(self): 43 if not hasattr(self, ‘_cookies‘): 44 cookies = {} 45 cookie_str = self._environ.get(‘HTTP_COOKIE‘) 46 if cookie_str: 47 for c in cookie_str.split(‘;‘): 48 pos = c.find(‘=‘) 49 if pos>0: 50 cookies[c[:pos].strip()] = _unquote(c[pos+1:]) 51 self._cookies = cookies 52 return self._cookies 53 @property 54 def cookies(self): 55 56 return Dict(**self._get_cookies()) 57 def cookie(self, name, default=None): 58 59 return self._get_cookies().get(name, default)
class Response(object):
def __init__(self):
self._status = ‘200 OK‘
self._headers = {‘CONTENT-TYPE‘: ‘text/html; charset=utf-8‘}
1 class WSGIApplication(object): 2 #初始化时创建后面要用到的属性 3 def __init__(self, document_root=None, **kw): 4 ‘‘‘ 5 Init a WSGIApplication. 6 Args: 7 document_root: document root path. 8 ‘‘‘ 9 10 self._running = False 11 self._document_root = document_root 12 self._interceptors = [] 13 self._template_engine = None 14 self._get_static = {} 15 self._post_static = {} 16 self._get_dynamic = [] 17 self._post_dynamic = [] 18 19 #用来查看服务器是否正在运行 20 def _check_not_running(self): 21 if self._running: 22 raise RuntimeError(‘Cannot modify WSGIApplication when running.‘) 23 #添加模板 24 @property 25 def template_engine(self): 26 return self._template_engine 27 @template_engine.setter 28 def template_engine(self, engine): 29 self._check_not_running() 30 self._template_engine = engine 31 32 #add_module()和add_url()用来将urls.py中的函数注册到服务器中 33 def add_module(self, mod): 34 self._check_not_running() 35 m = mod if type(mod)==types.ModuleType else _load_module(mod) 36 logging.info(‘Add module: %s‘ % m.__name__) 37 for name in dir(m): 38 fn = getattr(m, name) 39 if callable(fn) and hasattr(fn, ‘__web_route__‘) and hasattr(fn, ‘__web_method__‘): 40 self.add_url(fn) 41 def add_url(self, func): 42 self._check_not_running() 43 route = Route(func) 44 if route.is_static: 45 if route.method==‘GET‘: 46 self._get_static[route.path] = route 47 if route.method==‘POST‘: 48 self._post_static[route.path] = route 49 else: 50 if route.method==‘GET‘: 51 self._get_dynamic.append(route) 52 if route.method==‘POST‘: 53 self._post_dynamic.append(route) 54 logging.info(‘Add route: %s‘ % str(route)) 55 56 #添加拦截函数 57 def add_interceptor(self, func): 58 self._check_not_running() 59 self._interceptors.append(func) 60 logging.info(‘Add interceptor: %s‘ % str(func)) 61 62 #运行服务器 63 def run(self, port=9000, host=‘127.0.0.1‘): 64 from wsgiref.simple_server import make_server 65 logging.info(‘application (%s) will start at %s:%s...‘ % (self._document_root, host, port)) 66 #httpd = make_server(‘‘, 8000, hello_world_app) 其中self.get_wsgi_application(debug=True)便是代替hello_world_app, 67 #这个是一个函数对象wsgi, 可以被调用 68 server = make_server(host, port, self.get_wsgi_application(debug=True)) 69 server.serve_forever()
70 #这时这个应用中的核心 71 #返回值wsgi是一个函数对象,而不是一个确定值,主要是为了上面的调用 72 def get_wsgi_application(self, debug=False): 73 self._check_not_running() 74 if debug: 75 self._get_dynamic.append(StaticFileRoute()) 76 self._running = True 77 _application = Dict(document_root=self._document_root) 78 79 #这个函数的作用就是将注册的函数和请求的路径联系起来 80 def fn_route(): 81 request_method = ctx.request.request_method 82 path_info = ctx.request.path_info 83 if request_method==‘GET‘: 84 fn = self._get_static.get(path_info, None) 85 if fn: 86 #静态路径的话就可以直接调用函数: 87 return fn() 88 for fn in self._get_dynamic: 89 #如果是动态的路径,那么将其中的动态部分提取出来作为函数的参数: 90 args = fn.match(path_info) 91 if args: 92 return fn(*args) 93 raise notfound() 94 if request_method==‘POST‘: 95 fn = self._post_static.get(path_info, None) 96 if fn: 97 return fn() 98 for fn in self._post_dynamic: 99 args = fn.match(path_info) 100 if args: 101 return fn(*args) 102 raise notfound() 103 raise badrequest() 104 105 #添加拦截函数 106 fn_exec = _build_interceptor_chain(fn_route, *self._interceptors) 107 108 #wsgi就是应用程序了,其中的两个参数在wsgiref中会提供的: 109 def wsgi(env, start_response): 110 111 #将Request和Response实例化成为ctx的属性 112 ctx.application = _application 113 ctx.request = Request(env) 114 response = ctx.response = Response() 115 116 try: 117 118 r = fn_exec() 119 #正常情况下r是被包裹的函数返回的填入返回值的模板 120 if isinstance(r, Template): 121 r = self._template_engine(r.template_name, r.model) 122 if isinstance(r, unicode): 123 r = r.encode(‘utf-8‘) 124 if r is None: 125 r = [] 126 start_response(response.status, response.headers) 127 return r 128 #处理各种错误 129 except RedirectError, e: 130 response.set_header(‘Location‘, e.location) 131 start_response(e.status, response.headers) 132 return [] 133 except HttpError, e: 134 start_response(e.status, response.headers) 135 return [‘<html><body><h1>‘, e.status, ‘</h1></body></html>‘] 136 except Exception, e: 137 logging.exception(e) 138 if not debug: 139 start_response(‘500 Internal Server Error‘, []) 140 return [‘<html><body><h1>500 Internal Server Error</h1></body></html>‘] 141 exc_type, exc_value, exc_traceback = sys.exc_info() 142 fp = StringIO() 143 traceback.print_exception(exc_type, exc_value, exc_traceback, file=fp) 144 stacks = fp.getvalue() 145 fp.close() 146 start_response(‘500 Internal Server Error‘, []) 147 return [ 148 r‘‘‘<html><body><h1>500 Internal Server Error</h1><div style="font-family:Monaco, Menlo, Consolas, ‘Courier New‘, monospace;"><pre>‘‘‘, 149 stacks.replace(‘<‘, ‘<‘).replace(‘>‘, ‘>‘), 150 ‘</pre></div></body></html>‘] 151 #请求结束后将线程的各个属性删除 152 finally: 153 del ctx.application 154 del ctx.request 155 del ctx.response 156 return wsgi
标签:
原文地址:http://www.cnblogs.com/arvinls/p/4781606.html