Python中Web框架编写学习心得
2021-07-16 10:07
阅读:702
学习廖雪峰老师的Python实战教程,在Web框架这部分看了大致一个多礼拜,前面的知识学的不够扎实,由于比较复杂,因此在这里总结下,也算是巩固了。
先看下框架的调用代码:
app = web.Application(loop=loop, middlewares=[logger_factory, response_factory])
init_jinja2(app, filters=dict(datetime=datetime_filter))
add_routes(app, ‘handlers‘)
add_static(app)
- 使用web.Application类创建aiohttp server——app,其中loop为Eventloop用来处理HTTP请求,middlewares为中间件,在这里用来记录日志并处理handler返回的数据为web.response对象,这里看下
response_factory
的代码
async def response_factory(app, handler):
async def response(request):
logging.info(‘Response handler...‘)
#获取handler的返回值,根据返回值的不同类型进行处理
r = await handler(request)
print(type(r))
if isinstance(r, web.StreamResponse):
return r
if isinstance(r, bytes):
resp = web.Response(body=r)
resp.content_type = ‘application/octet-stream‘
return resp
if isinstance(r, str):
if r.startswith(‘redirect:‘):
return web.HTTPFound(r[9:])
resp = web.Response(body=r.encode(‘utf-8‘))
resp.content_type = ‘text/html;charset=utf-8‘
return resp
if isinstance(r, dict):
template = r.get(‘__template__‘)
if template is None:
resp = web.Response(body=json.dumps(r, ensure_ascii=False, default=lambda o: o.__dict__).encode(‘utf-8‘))
resp.content_type = ‘application/json;charset=utf-8‘
return resp
else:
resp = web.Response(body=app[‘__templating__‘].get_template(template).render(**r).encode(‘utf-8‘))
resp.content_type = ‘text/html;charset=utf-8‘
return resp
if isinstance(r, int) and r >= 100 and r 600:
return web.Response(r)
if isinstance(r, tuple) and len(r) == 2:
t, m = r
if isinstance(t, int) and t >= 100 and t 600:
return web.Response(t, str(m))
# default:
resp = web.Response(body=str(r).encode(‘utf-8‘))
resp.content_type = ‘text/plain;charset=utf-8‘
return resp
return response
- 使用jinjia2模板来构建前端页面,这里我们暂时没有用到
- 注册处理url的handler,aiohttp中的add_route函数进行注册,我们这里使用
add_routes
对‘handlers‘模块的handler进行批量注册
def add_route(app, fn):
method = getattr(fn, ‘__method__‘, None)
path = getattr(fn, ‘__route__‘, None)
if path is None or method is None:
raise ValueError(‘@get or @post not defined in %s.‘ % str(fn))
if not asyncio.iscoroutinefunction(fn) and not inspect.isgeneratorfunction(fn):
fn = asyncio.coroutine(fn)
logging.info(‘add route %s %s => %s(%s)‘ % (method, path, fn.__name__, ‘, ‘.join(inspect.signature(fn).parameters.keys())))
app.router.add_route(method, path, RequestHandler(app, fn))
def add_routes(app, module_name):
#找到‘.‘则返回其所在位置,否则返回-1
n = module_name.rfind(‘.‘)
if n == (-1):
#mod为包含module_name模块中全部属性和方法的list
mod = __import__(module_name, globals(), locals())
else:
name = module_name[n+1:]
mod = getattr(__import__(module_name[:n], globals(), locals(), [name]), name)
for attr in dir(mod):
#检查handler是否被@get或@post装饰
if attr.startswith(‘_‘):
continue
fn = getattr(mod, attr)
if callable(fn):
method = getattr(fn, ‘__method__‘, None)
path = getattr(fn, ‘__route__‘, None)
if method and path:
add_route(app, fn)
这里出现了一个RequestHandler类,它具有call魔术方法,所以可以像调用函数一样调用其实例,这里RequestHandler类主要是对handler进行封装,获取request中传入的参数并传入handler中。
- add_static是用户处理如图片、js、css等静态资源的,仅供开发环境中方便使用,生产环境一般使用nginx或CDN之类的,这块我也还没有搞清楚,没办法梳理
最后把我的handler模块的代码贴出来,供参考:
from coroweb import get, post
from aiohttp import web
@get(‘/blog‘)
async def handler_url_blog(request):
body=‘Awesome: /blog
‘
return body
@get(‘/greeting‘)
async def handler_url_greeting(*,name,request):
body=‘Awesome: /greeting %s
‘%name
return body
@get(‘/input‘)
async def handler_url_input(request):
body=‘‘
return body
@post(‘/result‘)
async def handler_url_result(*,user_email,request):
body=‘您输入的邮箱是%s
‘%user_email
return body
@get(‘/index‘)
async def handler_url_index(request):
body=‘Awesome: /index
‘
return body
@get(‘/create_comment‘)
async def handler_url_create_comment(request):
body=‘Awesome: /create_comment
‘
return body
评论
亲,登录后才可以留言!