web应用程序处理流程
- 用户通过客户端发送请求。
- 请求发送到web服务器上。
- web服务器将请求转交给web应用程序,web应用程序进行处理。
- web应用程序将请求结果返回给web服务器,由web服务器返回响应结果给客户端。
- 客户端收到响应结果,展示给用户。
可以看到,web服务器和web应用程序需要进行通信,但是web服务器有很多种(apache,Nginx,Lighttpd...),web应用程序开发框架也有很多种(Flask,Django...),如果没有统一标准进行通信,就会存在Web框架和Web服务器数据无法匹配的情况,那么开发就会受到限制,这显然不合理的。所以就有了WSGI规范,那么什么是WSGI呢?
WSGI
web服务器网关接口(Python Web Server Gateway Interface,简称WSGI),是为python定义的web服务器和web应用程序或框架之间的一种简单而通用的接口。它是一种规范,作用于web服务器和python应用程序之间,目的是保证不同的web服务器和不同的web应用程序或框架能够进行通信。
wsgi就像一个桥梁,连接着服务器和应用程序。
WSGI区分为两个部分:一为“服务器”或“网关”,另一为“应用程序”或“应用框架”。在处理一个WSGI请求时,服务器会为应用程序提供环境信息及一个回调函数。当应用程序完成处理请求后,透过前述的回调函数,将结果回传给服务器。
WSGI 相当于中间件同时实现了API的两方,因此可以在服务器和应用程序之间起调解作用:从Web服务器的角度来说,中间件扮演应用程序,而从应用程序的角度来说,中间件扮演服务器。
WSGI规定:
- web应用程序必须是一个可调用对象,必须接收两个参数,返回一个可迭代对象。
- 两个参数(由服务器提供):
environ:字典,包含请求的所有信息
start_response:在可调用对象中调用的函数,用来发起响应,参数包括状态码,headers等
根据这些规则,很容易写出一个遵循wsgi协议的app。
def application(environ, start_response):
status = "200 OK"
response_headers = [('Content-Type', 'text/html')]
start_response(status, response_headers)
return [b' hello world!
' ]
了解了WSGI,让我们从源码的角度来看一下Flask的工作原理。
Flask处理请求入口
我们知道,遵循WSGI协议的应用一定是一个可调用对象, 所以它既可以是一个函数, 也可以是一个实现了__call__()方法的类。
我们可以看一下Flask的源码。
class Flask(_PackageBoundObject):
...
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
flask在接收请求时,会执行__call__()方法,而__call__()方法会调用wsgi_app方法,这就是核心所在。
def wsgi_app(self, environ, start_response):
ctx = self.request_context(environ)
error = None
try:
try:
ctx.push()
response = self.full_dispatch_request()
except Exception as e:
error = e
response = self.handle_exception(e)
except: # noqa: B001
error = sys.exc_info()[1]
raise
return response(environ, start_response)
finally:
if self.should_ignore_error(error):
error = None
ctx.auto_pop(error)
这个就是Flask的真正请求入口了,该方法完成了请求和响应的处理,WSGI服务器通过调用该方法传入请求数据,获取返回数据。
我们看一下wsgi_app具体实现。
Flask处理请求的实现
- ctx = self.request_context(environ)和ctx.push()这里的代码是创建一个request对象和生成请求上下文环境。
- response = self.full_dispatch_request() 这部分实现了请求预处理,错误处理及请求转发到响应的过程。
- return response(environ, start_response) 这部分将响应结果返回给WSGI。
到此为止,WSGI和flask一次请求到响应完成了。