用户到我们web应用中间经过的相关协议,具体介绍和pyhton相关的WSGI和ASGI,我先把结论列出来,详细描述请看下面介绍!
请大家先记住这张图,带着问题和整个框架去看比较易于了解
CGI,WSGI,ASGI、框架以及Web服务器的关系:比如flask,这是一个同步框架,同时也是一个Web应用,一个请求需要经过Web服务器和WSGI服务器才能和框架“交流”数据。下面请看一张图来澄清整个链路
对这张图有一段话解释这里借鉴一下,参考[1]
首先nginx 是对外的服务接口,外部浏览器通过url访问nginx,
nginx 接收到浏览器发送过来的http请求,将包进行解析,分析url,如果是静态文件请求就直接访问用户给nginx配置的静态文件目录,直接返回用户请求的静态文件, 如果不是静态文件,而是一个动态的请求,那么nginx就将请求转发给uwsgi,uwsgi 接收到请求之后将包进行处理,处理成wsgi可以接受的格式,并发给wsgi,wsgi 根据请求调用应用程序的某个文件,某个文件的某个函数,最后处理完将返回值再次交给wsgi,wsgi将返回值进行打包,打包成uwsgi能够接收的格式,uwsgi接收wsgi 发送的请求,并转发给nginx,nginx最终将返回值返回给浏览器。
要知道第一级的nginx并不是必须的,uwsgi完全可以完成整个的和浏览器交互的流程,但是要考虑到某些情况
a. 安全问题,程序不能直接被浏览器访问到,而是通过nginx,nginx只开放某个接口,uwsgi本身是内网接口,这样运维人员在nginx上加上安全性的限制,可以达到保护程序的作用。
b. 负载均衡问题,一个uwsgi很可能不够用,即使开了多个work也是不行,毕竟一台机器的cpu和内存都是有限的,有了nginx做代理,一个nginx可以代理多台uwsgi完成uwsgi的负载均衡。
c. 静态文件问题,用django或是uwsgi这种东西来负责静态文件的处理是很浪费的行为,而且他们本身对文件的处理也不如nginx好,所以整个静态文件的处理都直接由nginx完成,静态文件的访问完全不去经过uwsgi以及其后面的东西。
通用型网关接口:CGI、FastCGI
网关接口是一种协议,为了实现加载动态脚本。CGI程序则是实现了CGI协议的一种程序
Web服务器网关接口协议:WSGI、ASGI、uwsgi
网关接口是用于Web应用与Web服务器进行通讯。其中WSGI、ASGI是专为python设计的网关接口。uwsgi是uWSGI服务器自有的传输协议
实现了Web服务器网关接口的软件有:uWSGI(注意大小写)、uvicorn、gunicorn
同步异步:同步是指执行是串行的,需要处理完当前任务在处理一下;异步指并行的,现有的任务不影响下一个任务的执行。类比到请求上面就是假如同时有两个请求进来,在同步处理的框架下第二个请求需要等第一个结束之后才能响应,而异步就可以并行处理
Web框架:
诸如Flask、Django这类pyhton Web框架,可以被启动当成服务器的原因,都是因为其自带启动了WSGI服务器,才允许Web服务器与Web框架之间进行连接。(效率极其低下,一般生产可以使用gunicorn、gevent等WSGI服务器)
这里请参考flask启动的案例,Flask.run()
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
"""Runs the application on a local development server.
Do not use ``run()`` in a production setting. It is not intended to
meet security and performance requirements for a production server.
Instead, see :ref:`deployment` for WSGI server recommendations.
****"""
* # 省略了部分代码
* # 省略了部分代码
* # 省略了部分代码
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
* # 省略了部分代码
* # 省略了部分代码
* # 省略了部分代码
这里注意到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,
):
"""Start a WSGI application. Optional features include a reloader,
multithreading and fork support."""
可以看到这里就是做启动WSGI服务的简单准备工作,具体代码就不分析,感兴趣的小伙伴可以去跟踪看下生成的过程
而FastAPI这类高性能、纯Web框架,是没有带WSGI或者ASGI协议的服务器启动功能的,所以我们在启动的时候需要用uvicorn等命令
总结:框架是为了让我们专注于逻辑代码和业务的实现,我们可以无需将时间和精力花在数据如何传输,如何编码,请求和响应是如何执行的。不过这中间可能会涉及到服务器之间的层层关系,所以我们有必要了解一下整个链路来龙去脉
协议,规范 支持的请求协议(常见,未列全) 同步/异步 支持的框架
CGI HTTP CGI程序
WSGI HTTP 同步 Flup,Flask
ASGI HTTP,HTTP2,WebSocket等 同步/异步 FastAPI,Quart,Sanic,Vibora,Tornado
CGI
CGI(Common Gateway Interface),通用网关接口,它是一种协议,是Web服务器和独立进程之间的协议,它会把HTTP请求的Request的Header设置成进程环境变量,HTTP请求的Body正文设置成进程的标准输入,进程的标准输出设置为HTTP响应的Response。
早期的Web服务器,只能响应浏览器发来的HTTP静态资源的请求,随着技术的发展,需要用到动态技术。由于Web服务器不能直接运行动态脚本,为了解决Web服务器与应用程序之间数据互通,出现了CGI。由于效率低下,不安全等原因,目前在生产环境基本被抛弃。
CGI程序
CGI(Common Gateway Interface)是一个接口规范或协议,实现其规范的程序叫做CGI程序。Web客户端发送HTTP请求到Web服务端,之后服务端通过CGI程序进行处理数据,处理完的结果在逐层返回,请看下图
我们常说的Web服务器一般是用于加载静态文件的请求,有一些动态脚本的请求,就会需要Web服务器创建一个新的进程来启动CGI程序,也就是CGI程序进行加载动态脚本,之后由Web服务器返回给客户端。
CGI程序可以是任何有标准输入和输出的脚本语言或者编程语言实现的,但由于其漏洞大,安全性低,每次有动态页面请求都会启动一个CGI程序,因此服务器压力特别大。逐渐出现了mod_perl、FastCGI等增强版本
WSGI
Web服务器网关接口(Python Web Server Gateway Interface),缩写为WSGI,它是一种专为python定义的接口规范,用于web服务端和web应用(框架)之间的连接,如此web应用可以一起处理一个请求,同时也是基于CGI进行设计的
通俗的理解,WSGI也是一种规范协议,主要是建立一个适用于服务器与Web框架之间的接口。那么跟CGI类似的,你可以通过自己的编程语言实现符合WSGI的应用程序,下面看一下WIKI上面的例子
def app(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
yield "Hello world!\n"
1
2
3
其中
第一行定义了一个名为 app 的 callable服务器网关接口#cite_note-2),接受两个参数,environ 和 start_response,environ 是一个字典包含了 CGI 中的环境变量。
第二行调用了start_response,状态指定为“200 OK”,消息头指定为内容类型是“text/plain”。start_response 也是一个 callable,接受两个必须的参数,status(HTTP 状态)和 response_headers(响应消息的头)。
第三行将响应消息的消息体返回。
这里的流程请注意:
Web客户端(浏览器)发送请求
HTTP服务器接收请求
实现了WSGI的服务器接收请求(可以和2合并)
a. 把环境变量和请求参数以及一个callback回调函数传递给Web应用程序
b. Web应用程序处理完之后通过回调函数返回给HTTP服务器
WSGI 协议包含两个部分,一个是 WSGI 服务器端(server),另一个则是应用程序端(application)。即 WSGI 对上文中的 Web 应用程序也有比较严格协议规定。固编写 Web 应用程序通常需要使用支持 WSGI 协议的应用框架,如 Django、Flask 等。
ASGI
异步网关接口(Asynchronous Server Gateway Interface),是WSGI的扩展版本,旨在为Python Web服务、框架和应用之间提供一个标准的异步接口。其本身可以提供同步和异步应用,并且可以并行处理。还能处理多种通用协议,包括HTTP,HTTP2和WebSocket。同WSGI一样,需要有独立的服务器实现这种异步的网关接口,比如Daphne、Uvicorn、Hypercorn等