• 20、廖雪峰Python实战Day5


    先贴上主函数代码:

    async def init(loop):
        await orm.create_pool(loop=loop, host='127.0.0.1', port=3306, user='root', password='root', db='awesome')    #1
        app = web.Application(loop=loop, middlewares=[    #2
            logger_factory, response_factory
        ])
        init_jinja2(app, filters=dict(datetime=datetime_filter))    #3
        add_routes(app, 'handlers')    #4
        add_static(app)    #5
        srv = await loop.create_server(app.make_handler(), '127.0.0.1', 9000)    #6
        logging.info('server started at http://127.0.0.1:9000...')
        return srv
    
    loop = asyncio.get_event_loop()
    loop.run_until_complete(init(loop))
    loop.run_forever()

    #1:创建数据库连接池;

    #2:创建Web Application对象,其中middlewares后面重点述说;

    #3:后期使用的模板框架;

    #4:添加handlers模块中的URL处理函数到Web Application的router中;

    #5:添加css等静态文件;

    #6:创建服务器接受处理请求;

    本节是一个重难点,各种查资料研究了一个多星期,整理心得体会如下:

    一、可参阅资料

    1、函数参数

    coroweb模块中各种判断handlers模块中的URL处理函数的参数(位置参数、默认参数、可变参数、关键字参数、命名关键字参数)

    廖雪峰Python教程之函数的参数

    2、inspect模块相关

    (1)【转载】python中inspect模块

    (2)【翻译】模块inspect — Inspect live objects

    3、特殊函数__call__

    Python特殊函数__call__

    4、aiohttp源码解析相关

    (1)aiohttp 源码解析之 request 的处理过程

    (2)python之aiohttp源码解析——add_route和middleware的工作方式

    5、本节廖雪峰Python教程

    Day 5 - 编写Web框架

    二、分析服务器接收request到处理的过程

    1、定义RequestHandler

    URL处理函数不一定是一个coroutine,因此我们用RequestHandler()来封装一个URL处理函数。

    RequestHandler是一个类,由于定义了__call__()方法,因此可以将其实例视为函数。

    RequestHandler目的就是从URL函数中分析其需要接收的参数,从request中获取必要的参数,调用URL函数,然后把结果转换为web.Response对象,这样,就完全符合aiohttp框架的要求:

    class RequestHandler(object):
    
        def __init__(self, app, fn):
            self._app = app
            self._func = fn
            ...
    
        async def __call__(self, request):
            ...
            try:
                r = await self._func(**kw)
             q   return r
            except APIError as e:
                ...

    再来分析下add_route函数:

    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))

    由此可知,针对请求method,path,处理函数是RequestHandler对象,构造函数中封装有真正的处理函数fn(handlers.py中,例如:def index()...),从RequestHandler类定义中的  r = await self._func(**kw) 也一样可以得出此结论(self._func = fn)。注意:此时URLHandler = RequestHandler (app, fn),因为定义了__call__函数,所以URLHandler(request), 可直接调用__call__函数来处理request。

    2、middleware

    middleware是一种拦截器,一个URL在被某个函数处理前,可以经过一系列的middleware的处理。

    一个middleware可以改变URL的输入、输出,甚至可以决定不继续处理而直接返回。middleware的用处就在于把通用的功能从每个URL处理函数中拿出来,集中放到一个地方。

    代码中middleware = [ logger_factory,  response_factory ]。

    截取《aiohttp 源码解析之 request 的处理过程》中针对middleware的处理源码:

    handler = match_info.handler # 这个handler就是我们先前注册的request的最终处理函数,即RequestHandler对象,因为定义了__call__,所以对象即函数
            for factory in reversed(self._middlewares):  #逆置
                handler = yield from factory(app, handler)
            # 重点来了,这里好像是在等待我们的 url 处理函数处理的结果啊
            resp = yield from handler(request)

    同时我们贴上两个相关函数:

    async def logger_factory(app, handler):
        async def logger(request):
            logging.info('Request: %s %s' % (request.method, request.path))
            return (await handler(request))
        return logger
    
    async def response_factory(app, handler):
        async def response(request):
            logging.info('Response handler...')
            r = await handler(request) 
            ...
            return resp
        return response

    for循环中出现多次handler 和 yield from语句,我们调试分析下:

    1、  handler = RequestHandler(app, fn)   (Function Object )
         factory = response_factory
    =>   handler = yield from factory(app, handler)
    =>                     response_factory(app, RequestHandler(app, fn))
    =>                     response
    
    2、  handler = response
         factory = logger_factory
    =>   handler = yield from factory(app, handler)
    =>                     logger_factory(app, response)
    =>                     logger

    所以此时handler = logger,当有request进来,调用语句 resp = yield from handler(request) 时,分析如下:

    通过await建立管道,实际的URL处理函数func处理完后,将结果层层返回,直至logger。

     

  • 相关阅读:
    C++中的命名空间
    [3D数学基础:图形与游戏开发]专栏前言
    Step01-题目申报
    《通用型云端物联网网关系统的设计与实现》
    博弈论题目总结(一)——简单组合游戏
    单纯形模板
    BZOJ 3434 [WC2014]时空穿梭 (莫比乌斯反演)
    BZOJ 3533 [SDOI2014]向量集 (线段树维护凸包)
    BZOJ 2161 布娃娃 (主席树)
    UOJ #86 mx的组合数 (数位DP+NTT+原根优化)
  • 原文地址:https://www.cnblogs.com/zwb8848happy/p/8975206.html
Copyright © 2020-2023  润新知