Flask -- werkzeug请求与响应以及源码的解析
werkzeug:
Flask框架内部本身没有实现socket,而是使用wsgi实现。wsgi是web服务网管接口,能够对请求进行封装、解析。
基于werkzeug的web应用:
# 方式一:Flask返回对象是Response, 继承于werkzeug的BaseResponse。
from werkzeug.serving import run_simple
from werkzeug.wrappers import BaseResponse
def hello(environ, start_response):
# environ, start_response参数在下面有说明
response = BaseResponse('Hello World!')
return response(environ, start_response)
if __name__ == '__main__':
run_simple('127.0.0.1', 5000, hello)
# 方式二:
from werkzeug.wrappers import Request, Response
@Request.application
def hello(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, hello)
源码分析:
-
首先看一下初始化
__init__.py
类,它重新构造object_origins
字典数据格式,列举了以下键值对:# BaseResponse - --- werkzeug.wrappers # BaseRequest - --- werkzeug.wrappers # Request - --- werkzeug.wrappers # Response - --- werkzeug.wrappers # 该字典的键是werkzeug下的某模块中的函数、方法,值是werkzeug下的某模块
-
在文件起始处我们引入了
from werkzeug.serving import run_simple
跟踪代码去看下serving.py
模块下的run_simple
函数def run_simple(hostname, port, application, use_reloader=False, use_debugger=False, use_evalex=True, extra_files=None, reloader_interval=1, reloader_type='auto', threaded=False, processes=1, request_handler=None, static_files=None, passthrough_errors=False, ssl_context=None)
参数的意思:
hostname:应用程序的主机 port:端口 application:WSGI应用程序 use_reloader:如果程序代码修改,是否需要自动启动服务 use_debugger:程序是否要使用工具和调试系统 use_evalex:应用是否开启异常评估 extra_files:重载器应该查看的文件列表附加到模块。例如配置文件夹 reloader_interval:秒重载器的间隔 reloader_type:重载器的类型 threaded:进程是否处理单线程的每次请求 processes:如果大于1,则在新进程中处理每个请求。达到这个最大并发进程数 request_handler:可以自定义替换BaseHTTPRequestHandler static_files:静态文件路径的列表或DICT passthrough_errors:将此设置为“真”以禁用错误捕获。这意味着服务器会因错误而死亡 ssl_context:如何进行传输数据加密,可以设置的环境if use_reloader:
-
run_simple
函数中,通过if use_reloader
判断,会执行inner()
方法,def inner(): try: fd = int(os.environ["WERKZEUG_SERVER_FD"]) except (LookupError, ValueError): fd = None srv = make_server( hostname, port, application, threaded, processes, request_handler, passthrough_errors, ssl_context, fd=fd, ) if fd is None: log_startup(srv.socket) srv.serve_forever()
-
通过
make_server
方法, 跟进我们在初始化__init__
中的参数,去构造server服务 。def make_server( host=None, port=None, app=None, threaded=False, processes=1, request_handler=None, passthrough_errors=False, ssl_context=None, fd=None, ): """Create a new server instance that is either threaded, or forks or just processes one request after another. """ if threaded and processes > 1: raise ValueError("cannot have a multithreaded and multi process server.") elif threaded: return ThreadedWSGIServer( host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd ) elif processes > 1: return ForkingWSGIServer( host, port, app, processes, request_handler, passthrough_errors, ssl_context, fd=fd, ) else: return BaseWSGIServer( host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd )
-
然后在
inner
方法中,srv.serve_forever()
使服务运行起来 。 -
当
run_simple('localhost', 4000, hello)
执行后,在http://localhost:4000/
请求到来时,就会触发Response('Hello World!')
-
接下来我们看一下
werkzeug.wrappers.py
模块下的Response
类class Response( BaseResponse, ETagResponseMixin, ResponseStreamMixin, CommonResponseDescriptorsMixin, WWWAuthenticateMixin, )
-
该类是多重继承类,主要看一下
BaseResponse
:首先
__init__
初始化时,定义了返回的Headers
、content_type
、状态码status
等.def __init__( self, response=None, status=None, headers=None, mimetype=None, content_type=None, direct_passthrough=False, )
最后通过
self.set_data(response)
,跟踪代码如下:def set_data(self, value): """Sets a new string as response. The value set must either by a unicode or bytestring. If a unicode string is set it's encoded automatically to the charset of the response (utf-8 by default). .. versionadded:: 0.9 """ # if an unicode string is set, it's encoded directly so that we # can set the content length if isinstance(value, text_type): value = value.encode(self.charset) else: value = bytes(value) self.response = [value] if self.automatically_set_content_length: self.headers["Content-Length"] = str(len(value))
我们在例子中的
Response('Hello World!')
参数字符串,会以bytes
类型进行数据的传输。 -
然后执行
对象()
,会调用__call__
方法, 会返回一个应用程序迭代器def __call__(self, environ, start_response): """Process this response as WSGI application. :param environ: the WSGI environment. :param start_response: the response callable provided by the WSGI server. :return: an application iterator """ app_iter, status, headers = self.get_wsgi_response(environ) start_response(status, headers) return app_iter
最上面的例子中,environ
参数是包含了请求的所有信息,start_response
是 application 请求处理完之后需要调用的函数,参数是状态码、响应头部还有错误信息 。