Web架构各层理解
客户端从发送一个 HTTP 请求到 Flask 处理请求,分别经过了 web服务器层,WSGI层,web框架层,这三个层次。不同的层次其作用也不同
Web服务器层
对于传统的客户端 - 服务器架构,其请求的处理过程是,客户端向服务器发送请求,服务器接收请求并处理请求,然后给客户端返回响应。在这个过程中,服务器的作用是:
- 接收请求
- 处理请求
- 返回响应
Web服务器是一类特殊的服务器,其作用是主要是接收 HTTP 请求并返回响应。提起 web服务器大家都不会陌生,常见的 web服务器有 Nginx,Apache,IIS等。在上图1的三层结构中,web服务器是最先接收用户请求的,并将响应结果返回给用户。
Web应用框架层
Web框架的作用主要是方便我们开发 web应用程序,HTTP请求的动态数据就是由 web框架层来提供的。常见的 web框架有Flask,Django等,我们以 Flask 框架为例子,展示 web框架的作用:
1 | from flask import Flask |
以上简单的几行代码,就创建了一个 web应用程序对象 app
。app
监听机器所有 ip 的 8080 端口,接受用户的请求连接。我们知道,HTTP 协议使用 URL 来定位资源,上面的程序会将路径 /hello
的请求交由 hello_world
方法处理,hello_world
返回 ‘Hello World!’ 字符串。对于 web框架的使用者来说,他们并不关心如何接收 HTTP 请求,也不关心如何将请求路由到具体方法处理并将响应结果返回给用户。Web框架的使用者在大部分情况下,只需要关心如何实现业务的逻辑即可
WSGI层
Web Server Gateway Interface 的缩写,即 Web 服务器网关接口
WSGI 不是服务器,也不是用于与程序交互的API,更不是真实的代码,WSGI 只是一种接口,它只适用于 Python 语言,其全称为 Web Server Gateway Interface,定义了 web服务器和 web应用之间的接口规范。也就是说,只要 web服务器和 web应用都遵守WSGI协议,那么 web服务器和 web应用就可以随意的组合。下面的代码展示了 web服务器是如何与 web应用组合在一起的。
1 | def application(env, start_response): |
方法 application
由 web服务器调用,参数env
,start_response
由 web服务器实现并传入。其中,env
是一个字典,包含了类似 HTTP_HOST,HOST_USER_AGENT,SERVER_PROTOCO 等环境变量。start_response
则是一个方法,该方法接受两个参数,分别是status
,response_headers
。application
方法的主要作用是,设置 http 响应的状态码和 Content-Type 等头部信息,并返回响应的具体结果。
上述代码就是一个完整的 WSGI 应用,当一个支持 WSGI 的 web服务器接收到客户端的请求后,便会调用这个 application
方法。WSGI 层并不需要关心env
,start_response
这两个变量是如何实现的,就像在 application
里面所做的,直接使用这两个变量即可。
值得指出的是,WSGI 是一种协议,需要区分几个相近的名词:
- uwsgi
同 wsgi 一样也是一种协议,uWSGI服务器正是使用了 uwsgi 协议 - uWSGI
实现了 uwsgi 和 WSGI 两种协议的web服务器。注意 uWSGI 本质上也是一种 web服务器,处于上面描述的三层结构中的 web服务器层。 - CGI
通用网关接口,并不限于 Python 语言,定义了 web服务器是如何向客户端提供动态的内容。例如,规定了客户端如何将参数传递给 web服务器,web服务器如何将参数传递给 web应用,web应用如何将它的输出如何发送给客户端,等等。
生产环境下的 web应用都不使用 CGI 了,CGI进程(类似 Python 解释器)针对每个请求创建,用完就抛弃,效率低下。WSGI 正是为了替代 CGI 而出现的。
说到这,我们基本理清了 WSGI 在 web服务器与 web框架之间作用:WSGI 就像一条纽带,将 web服务器与 web框架连接起来。回到本文的题目,Nginx 属于一种 web服务器,Flask属于一种 web框架,因此,WSGI 与 Nginx、Flask 的作用就不明而喻了。
最后以 Nginx,WSGI,Flask 之间的对话结束本文。
Nginx:Hey,WSGI,我刚收到了一个请求,我需要你作些准备,然后由Flask来处理这个请求。
WSGI:OK,Nginx。我会设置好环境变量,然后将这个请求传递给Flask处理。
Flask:Thanks WSGI!给我一些时间,我将会把请求的响应返回给你。
WSGI:Alright,那我等你。
Flask:Okay,我完成了,这里是请求的响应结果,请求把结果传递给Nginx。
WSGI:Good job!Nginx,这里是响应结果,已经按照要求给你传递回来了。
Nginx:Cool,我收到了,我把响应结果返回给客户端。大家合作愉快~
为什么使用WSGI
我们现在使用 Python 编写 Web 应用,
-
可以用比较流行的 Flask、Django 框架,也可以按自己的想法直接写一个。
-
可选的服务器软件也特别多,比如常见的有 Apache、Nginx、IIS 等,
-
除此外,也有很多小众的软件。
但是,现在问题来了,我该怎么部署?在没有 WSGI 规范之前,一个服务器调度 Python 应用是用这种方式,另一款服务器使用的是那种方式,这样的话,编写出来的应用部署时只能选择局限的某个或某些服务器,达不到通用的效果。
只有python是WSGI
WSGI(Web Server Gateway Interface)是Python的一种Web应用程序标准接口,它定义了Web服务器和用户程序之间的一种通信规范。
WSGI的出现是为了解决Python Web框架的兼容性问题,同时也使Python Web应用程序与多种Web服务器进行了兼容。
其他技术栈的Web框架与WSGI之间的关系可能会有所不同。
- 比如JavaEE使用的是Servlet规范,而不是WSGI。
- 对于PHP,Apache一般采用mod_php方式运行,PHP和Apache之间的通信过程也与WSGI不同。
- Node.js使用的是HTTP模块。 关于JavaEE容器和CGI/FastCGI,它们与WSGI有类似之处,都可以作为与Web服务器通信的中间件。
- JavaEE容器会处理Servlet或JSP程序,而CGI/FastCGI会处理PHP、Perl等脚本语言。
- 不过,它们的使用场景不同,JavaEE容器和CGI/FastCGI大多用于处理动态生成的Web页面,而WSGI则更适用于处理Python Web应用的请求。
总的来说,WSGI并不是Tomcat等JavaEE容器、CGI/FastCGI的替代实现,它只是一种Python Web应用程序标准接口。它的出现是为了使Python Web框架之间能够进行互操作,并且与多种Web服务器兼容。
自定义实现web应用
上面的服务器和应用整体是跑起来了,那么我换一个服务器或者应用呢。由于服务器与应用之间怎么交互完全没有规范,比如服务器应该如何把请求信息传给应用,应用处理完毕后又怎么告诉服务器开始返回响应,如果都是各搞各的,服务器需要定制应用,应用也要定制服务器,这要一个应用能跑起来也太麻烦了点吧。
所以,WSGI 的出现就是为了解决上面的问题,它规定了服务器怎么把请求信息告诉给应用,应用怎么把执行情况回传给服务器,这样的话,服务器与应用都按一个标准办事,只要实现了这个标准,服务器与应用随意搭配就可以,灵活度大大提高。
参考
- 转载
- 如何理解Nginx, WSGI, Flask之间的关系 | Leo的博客 (leehao.me)
- 为什么只有Python有WSGI? - 谈天吉皮提的回答 - 知乎 https://www.zhihu.com/question/598727285/answer/3009633117
- 说说我对 WSGI 的理解 - 知乎 (zhihu.com)