tornado-业务流程

tornado处理每一个请求,都过经过HTTPServer,然后实例化HTTPConnection,读取和解析HTTP包。通过URL在Application找到相应的RequestHandler,然后处理请求。

整个流程如如下图所示,


上图涉及到了多个类,下面就讲解主要的代码步骤


首先HTTPServe继承TcpServer,复写了handle_stream方法,当底层每次有新的请求连接时,就会调用。

?
1
2
3
4
5
6
7
def  handle_stream( self , stream, address):
         context  =  _HTTPRequestContext(stream, address,
                                       self .protocol)
         conn  =  HTTP1ServerConnection(
             stream,  self .conn_params, context)
         self ._connections.add(conn)
         conn.start_serving( self )

_HTTPRequestContext类是用来解析ip地址,协议的。

然后实例化HTTPServerConnection类,这个类主要负责对连接的处理。最后调用conn.start_serving方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def  start_serving( self , delegate):
         """Starts serving requests on this connection.
 
         :arg delegate: a `.HTTPServerConnectionDelegate`
         """
         assert  isinstance (delegate, httputil.HTTPServerConnectionDelegate)
         self ._serving_future  =  self ._server_request_loop(delegate)
         # Register the future on the IOLoop so its errors get logged.
         self .stream.io_loop.add_future( self ._serving_future,
                                        lambda  f: f.result())
 
     @gen.coroutine
     def  _server_request_loop( self , delegate):
         try :
             while  True :
                 conn  =  HTTP1Connection( self .stream,  False ,
                                        self .params,  self .context)
                 request_delegate  =  delegate.start_request( self , conn)
                 try :
                     ret  =  yield  conn.read_response(request_delegate)
                 except  (iostream.StreamClosedError,
                         iostream.UnsatisfiableReadError):
                     return
                 except  _QuietException:
                     # This exception was already logged.
                     conn.close()
                     return
                 except  Exception:
                     gen_log.error( "Uncaught exception" , exc_info = True )
                     conn.close()
                     return
                 if  not  ret:
                     return
                 yield  gen.moment
         finally :
             delegate.on_close( self )

可以看到start_serving方法,主要是调用了_server_request_loop方法。_server_request_loop方法被gen.coroutine装饰,说明这个函数是异步调用。

主要delegate这个函数参数,它指向HTTPServer。这里需要说明下一,HTTPServer和Application是怎么联系的。

由上图可以看出_ServerRequestAdapter类是_RequestDispatcher类的代理。HTTPServer和Application是通过这两个类关联一起的。


继续回到_server_request_loop函数里。它首先实例化了HTTP1Connection类,然后等带conn.read_response方法,返回结果。

继续看HTTP1Connection的read_response方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def  read_response( self , delegate):
         """Read a single HTTP response.
 
         Typical client-mode usage is to write a request using `write_headers`,
         `write`, and `finish`, and then call ``read_response``.
 
         :arg delegate: a `.HTTPMessageDelegate`
 
         Returns a `.Future` that resolves to None after the full response has
         been read.
         """
         if  self .params.decompress:
             delegate  =  _GzipMessageDelegate(delegate,  self .params.chunk_size)
         return  self ._read_message(delegate)

这里_GzipMessageDelegate是一个装饰类(装饰者模式),负责内容的gzip解码。

_read_message代码比较多,注意分为几个部分,一是读取http的首部,然后调用delegate.header_received。

然后读取http的body,最后调用delegate.finish。下面简化下代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#试图从stream读取到连续两个行结束符。因为连续两个行结束符意味着HEADER部分已经完成
header_future  =  self .stream.read_until_regex(
                 b "\r?\n\r?\n" ,
                 max_bytes = self .params.max_header_size)
#解析首部
start_line, headers  =  self ._parse_headers(header_data)     
 
#调用delegate.header_received
delegate.headers_received(start_line, headers)
 
#试图读取body
body_future  =  self ._read_body(
                     start_line.code  if  self .is_client  else  0 , headers, delegate)       
 
#调用delegate.finish                    
delegate.finish()


接下来看看_RequestDispatcher的实现,他负责主要的逻辑。

?
1
2
3
4
5
6
7
8
9
10
11
def  headers_received( self , start_line, headers):
         self .set_request(httputil.HTTPServerRequest(
             connection = self .connection, start_line = start_line, headers = headers))
         if  self .stream_request_body:
             self .request.body  =  Future()
             return  self .execute()
 
     def  set_request( self , request):
         self .request  =  request
         self ._find_handler()
         self .stream_request_body  =  _has_stream_request_body( self .handler_class)

header_received会实例化HTTPServerRequest,这个对象就是RequestHandler的request属性。

_find_handler就是调用Application的_get_host_handlers方法,找到相应的RequestHandler的子类。


?
1
2
3
4
5
6
7
def  finish( self ):
         if  self .stream_request_body:
             self .request.body.set_result( None )
         else :
             self .request.body  =  b''.join( self .chunks)
             self .request._parse_body()
             self .execute()

这里self.stream_request_body,只有在相应的RequestHandler被stream_request_body装饰,才会返回True。

所以这里会执行self.excute()方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
def  execute( self ):
         # If template cache is disabled (usually in the debug mode),
         # re-compile templates and reload static files on every
         # request so you don't need to restart to see changes
         if  not  self .application.settings.get( "compiled_template_cache" True ):
             with RequestHandler._template_loader_lock:
                 for  loader  in  RequestHandler._template_loaders.values():
                     loader.reset()
         if  not  self .application.settings.get( 'static_hash_cache' True ):
             StaticFileHandler.reset()
 
         self .handler  =  self .handler_class( self .application,  self .request,
                                           * * self .handler_kwargs)
         transforms  =  [t( self .request)  for  in  self .application.transforms]
 
         if  self .stream_request_body:
             self .handler._prepared_future  =  Future()
         # Note that if an exception escapes handler._execute it will be
         # trapped in the Future it returns (which we are ignoring here).
         # However, that shouldn't happen because _execute has a blanket
         # except handler, and we cannot easily access the IOLoop here to
         # call add_future (because of the requirement to remain compatible
         # with WSGI)
         =  self .handler._execute(transforms,  * self .path_args,  * * self .path_kwargs)
         f.add_done_callback( lambda  f: f.exception())
         # If we are streaming the request body, then execute() is finished
         # when the handler has prepared to receive the body.  If not,
         # it doesn't matter when execute() finishes (so we return None)
         return  self .handler._prepared_future

注意到这几步骤,

?
1
2
3
4
5
6
7
8
#实例化RequestHandler的子类
self .handler  =  self .handler_class( self .application,  self .request,
                                           * * self .handler_kwargs)
#包装request,用于http中传输                                         
transforms  =  [t( self .request)  for  in  self .application.transforms] 
 
#调用RequestHandler的_execute方法
self .handler._execute(transforms,  * self .path_args,  * * self .path_kwargs)


最后来看看Requesthandler的_execute方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@gen .coroutine
     def  _execute( self , transforms,  * args,  * * kwargs):
         """Executes this request with the given output transforms."""
         self ._transforms  =  transforms
         try :
             if  self .request.method  not  in  self .SUPPORTED_METHODS:
                 raise  HTTPError( 405 )
             self .path_args  =  [ self .decode_argument(arg)  for  arg  in  args]
             self .path_kwargs  =  dict ((k,  self .decode_argument(v, name = k))
                                     for  (k, v)  in  kwargs.items())
             # If XSRF cookies are turned on, reject form submissions without
             # the proper cookie
             if  self .request.method  not  in  ( "GET" "HEAD" "OPTIONS" and  \
                     self .application.settings.get( "xsrf_cookies" ):
                 self .check_xsrf_cookie()
 
             result  =  self .prepare()
             if  is_future(result):
                 result  =  yield  result
             if  result  is  not  None :
                 raise  TypeError( "Expected None, got %r"  %  result)
             if  self ._prepared_future  is  not  None :
                 # Tell the Application we've finished with prepare()
                 # and are ready for the body to arrive.
                 self ._prepared_future.set_result( None )
             if  self ._finished:
                 return
 
             if  _has_stream_request_body( self .__class__):
                 # In streaming mode request.body is a Future that signals
                 # the body has been completely received.  The Future has no
                 # result; the data has been passed to self.data_received
                 # instead.
                 try :
                     yield  self .request.body
                 except  iostream.StreamClosedError:
                     return
 
             method  =  getattr ( self self .request.method.lower())
             result  =  method( * self .path_args,  * * self .path_kwargs)
             if  is_future(result):
                 result  =  yield  result
             if  result  is  not  None :
                 raise  TypeError( "Expected None, got %r"  %  result)
             if  self ._auto_finish  and  not  self ._finished:
                 self .finish()
         except  Exception as e:
             self ._handle_request_exception(e)
             if  ( self ._prepared_future  is  not  None  and
                     not  self ._prepared_future.done()):
                 # In case we failed before setting _prepared_future, do it
                 # now (to unblock the HTTP server).  Note that this is not
                 # in a finally block to avoid GC issues prior to Python 3.4.
                 self ._prepared_future.set_result( None )


注意这几个步骤:

?
1
2
3
4
5
6
7
8
9
10
#调用prepare
result  =  self .prepare()
 
#找到相应的方法,并且调用
method  =  getattr ( self self .request.method.lower())
result  =  method( * self .path_args,  * * self .path_kwargs)
 
#自动调用self.finish
if  self ._auto_finish  and  not  self ._finished:
                 self .finish()


从Http请求过来,tornado会进行相应的处理。根据上面的流程,就可以比较清楚的弄清tornado的结构,然后逐步细细分析每一步。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值