一文读懂WSGI和ASGI

这一章谈谈用户到我们web应用中间经过的相关协议,具体介绍和pyhton相关的WSGI和ASGI,我先把结论列出来,详细描述请看下面介绍!

请大家先记住这张图,带着问题和整个框架去看比较易于了解

CGI,WSGI,ASGI、框架以及Web服务器的关系:比如flask,这是一个同步框架,同时也是一个Web应用,一个请求需要经过Web服务器和WSGI服务器才能和框架“交流”数据。下面请看一张图来澄清整个链路
在这里插入图片描述
对这张图有一段话解释这里借鉴一下,参考[1]

  1. 首先nginx 是对外的服务接口,外部浏览器通过url访问nginx,

  2. nginx 接收到浏览器发送过来的http请求,将包进行解析,分析url,如果是静态文件请求就直接访问用户给nginx配置的静态文件目录,直接返回用户请求的静态文件, 如果不是静态文件,而是一个动态的请求,那么nginx就将请求转发给uwsgi,uwsgi 接收到请求之后将包进行处理,处理成wsgi可以接受的格式,并发给wsgi,wsgi 根据请求调用应用程序的某个文件,某个文件的某个函数,最后处理完将返回值再次交给wsgi,wsgi将返回值进行打包,打包成uwsgi能够接收的格式,uwsgi接收wsgi 发送的请求,并转发给nginx,nginx最终将返回值返回给浏览器。

  3. 要知道第一级的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等命令

总结:框架是为了让我们专注于逻辑代码和业务的实现,我们可以无需将时间和精力花在数据如何传输,如何编码,请求和响应是如何执行的。不过这中间可能会涉及到服务器之间的层层关系,所以我们有必要了解一下整个链路来龙去脉

协议,规范支持的请求协议(常见,未列全)同步/异步支持的框架
CGIHTTPCGI程序
WSGIHTTP同步Flup,Flask
ASGIHTTP,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"

其中

  • 第一行定义了一个名为 app 的 callable服务器网关接口#cite_note-2),接受两个参数,environ 和 start_response,environ 是一个字典包含了 CGI 中的环境变量。
  • 第二行调用了start_response,状态指定为“200 OK”,消息头指定为内容类型是“text/plain”。start_response 也是一个 callable,接受两个必须的参数,status(HTTP 状态)和 response_headers(响应消息的头)。
  • 第三行将响应消息的消息体返回。

这里的流程请注意:

  1. Web客户端(浏览器)发送请求

  2. HTTP服务器接收请求

  3. 实现了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等,参考[3]

参考:

[1]: https://blog.csdn.net/u014761344/article/details/40146597 - nginx uwsgi wsgi django是什么关系

[2]: https://www.cnblogs.com/wongbingming/p/11002978.html - WSGI详细讲解

[3]: https://asgi.readthedocs.io/en/latest/implementations.html - ASGI实现相关

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值