首先要了解 WSGI 规范的概念,WSGI(Web Server Gateway Interface)规范描述了web server(Gunicorn,uWSGI等)如何与web application(flask, django等)交互、web application如何处理请求,定义在 pep 3333。正是有了 WSGI 规范,咱们才能在任意 web server 上跑各类 web 应用。WSGI API 定义看起来很简单:html
def application(environ, start_response)
复制代码
application 就是 WSGI app,一个可调用对象python
参数:web
函数返回值为响应体的迭代器 ###简单举例 下面举个简单的例子,好比一个返回 hello world 的应用:django
def application(environ, start_response):
status = '200 OK'
headers = [('Content-Type', 'text/html; charset=utf8')]
start_response(status, headers)
return [b"<h1>Hello, World!</h1>"]
复制代码
werkzeug是Python实现的WSGI规范的使用函数库。 正如werkzeug官网Werkzeug上所说,werkzeug使用起来很是简单,可是却很是强大。关于使用简单的这个特性,官网给了一段示例代码。flask
from werkzeug.wrappers import Request, Response
@Request.application
def application(request):
return Response('Hello World!')
if __name__ == '__main__':
from werkzeug.serving import run_simple
run_simple('localhost', 4000, application)
复制代码
###简单小结 关于上面的代码我作一下总结: application
--可调用对象,wsig模块中加括号括号执行 application
的返回值--Response对象,wsgi中会对该对象加括号执行其__call__
方法 一次成功的访问,由如下几步完成浏览器
具体来讲:bash
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):
def log_startup(sock):
display_hostname = hostname not in ('', '*') and hostname or 'localhost'
if ':' in display_hostname:
display_hostname = '[%s]' % display_hostname
quit_msg = '(Press CTRL+C to quit)'
port = sock.getsockname()[1]
_log('info', ' * Running on %s://%s:%d/ %s',
ssl_context is None and 'http' or 'https',
display_hostname, port, quit_msg)
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()
inner()
复制代码
执行inner
方法 而后执行make_server方法拿到其返回值并赋值给srv服务器
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)
复制代码
以BaseWSGIServer类为例,将其实例化就是执行其__init__
方法 由于类的各类继承,我就不一一细说了: 总的来讲:app
就是建立socket和定义处理request的类RequestHandleClass
其为:WSGIRequestHandler,本身看一下源码找一下吧
复制代码
而后执行srv.server_forver
srv
为BaseWSGIServer
的实例,根据类的继承,去查找各类方法. 记住一点就是查找方法优先从本身的类定义中找,若是没有就去父类中找.时刻谨记self是谁框架
#BaseWSGIServer中定义
def serve_forever(self):
self.shutdown_signal = False
try:
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()
复制代码
###BaseServer
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)
while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()
self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
复制代码
# BaseServer
def _handle_request_noblock(self):
"""Handle one request, without blocking. I assume that selector.select() has returned that the socket is readable before this function was called, so there should be no risk of blocking in get_request(). """
try:
request, client_address = self.get_request()
except OSError:
return
if self.verify_request(request, client_address):
try:
self.process_request(request, client_address)
except Exception:
self.handle_error(request, client_address)
self.shutdown_request(request)
except:
self.shutdown_request(request)
raise
else:
self.shutdown_request(request)
复制代码
执行process_request方法
def process_request(self, request, client_address):
"""Call finish_request. Overridden by ForkingMixIn and ThreadingMixIn. """
self.finish_request(request, client_address)
self.shutdown_request(request)
复制代码
Next
def finish_request(self, request, client_address):
"""Finish one request by instantiating RequestHandlerClass."""
self.RequestHandlerClass(request, client_address, self)
复制代码
执行RequestHandlerClass类的实例化
执行BaseHTTPRequestHandler的handle方法 WSGIRequestHandler.handle_one_request
def handle_one_request(self):
"""Handle a single HTTP request."""
self.raw_requestline = self.rfile.readline()
if not self.raw_requestline:
self.close_connection = 1
elif self.parse_request():
return self.run_wsgi()
复制代码
def run_wsgi(self):
if self.headers.get('Expect', '').lower().strip() == '100-continue':
self.wfile.write(b'HTTP/1.1 100 Continue\r\n\r\n')
self.environ = environ = self.make_environ()
headers_set = []
headers_sent = []
def write(data):
assert headers_set, 'write() before start_response'
if not headers_sent:
status, response_headers = headers_sent[:] = headers_set
try:
code, msg = status.split(None, 1)
except ValueError:
code, msg = status, ""
code = int(code)
self.send_response(code, msg)
header_keys = set()
for key, value in response_headers:
self.send_header(key, value)
key = key.lower()
header_keys.add(key)
if not ('content-length' in header_keys or
environ['REQUEST_METHOD'] == 'HEAD' or
code < 200 or code in (204, 304)):
self.close_connection = True
self.send_header('Connection', 'close')
if 'server' not in header_keys:
self.send_header('Server', self.version_string())
if 'date' not in header_keys:
self.send_header('Date', self.date_time_string())
self.end_headers()
assert isinstance(data, bytes), 'applications must write bytes'
self.wfile.write(data)
self.wfile.flush()
def start_response(status, response_headers, exc_info=None):
if exc_info:
try:
if headers_sent:
reraise(*exc_info)
finally:
exc_info = None
elif headers_set:
raise AssertionError('Headers already set')
headers_set[:] = [status, response_headers]
return write
def execute(app): # app_iter对象 包含了须要返回的各项数据
application_iter = app(environ, start_response) # Flask实例的call方法返回的的response对象的__call__方法返回的东西
try:
for data in application_iter:
write(data)
if not headers_sent:
write(b'')
finally:
if hasattr(application_iter, 'close'):
application_iter.close()
application_iter = None
try:
execute(self.server.app)
except (socket.error, socket.timeout) as e:
self.connection_dropped(e, environ)
except Exception:
if self.server.passthrough_errors:
raise
from werkzeug.debug.tbtools import get_current_traceback
traceback = get_current_traceback(ignore_system_exceptions=True)
try:
# if we haven't yet sent the headers but they are set
# we roll back to be able to set them again.
if not headers_sent:
del headers_set[:]
execute(InternalServerError())
except Exception:
pass
self.server.log('error', 'Error on request:\n%s',
traceback.plaintext)
复制代码
经过这个代码,咱们拿到了app执行后拿到的可迭代对象 application_iter = app(environ, start_response) # Flask实例的call方法返回的的response对象的__call__方法返回的可迭代对象
最终for循环这个对象发送了数据
for data in application_iter:
write(data)
复制代码