ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python进阶开发之理解WSGI(上)

2020-11-23 07:01:48  阅读:184  来源: 互联网

标签:__ WSGI 进阶 headers Python start environ response


image.png


本文目录



  • 什么是WSGI?

  • 如何实现Application?

  • 如何实现Web Server?

  • Web Server如何决择?


. 什么是WSGI?

WSGI(Web Server Gateway Interface),顾名思义,它既不是服务器,也不是应用,而是一种接口(规范),描述web server如何与web application通信的规范。

那么这个规范是什么?

  1. 服务器的请求处理要调用符合WSGI规范的网关接口;

  2. 由网关接口来调用应用程序,并且其要定义start_response(status, headers)函数,用于返回响应;

  3. 应用程序须是一个可调用对象(函数/类),webapp(environ, start_response)。接受两个参数,environ是环境设置的字典,由服务器和WSGI网关接口设置,start_response是由网关接口定义的函数。

在这个规范中,有三个角色

  • web server:实现了WSGI server协议的服务器

  • Gateway Interface:网关接口

  • application:实现了WSGI application协议的框架

常见的web serveruWSGIGunicorn

常见的 Gateway Interface 有CGIWSGI

常见的application框架有 DjangoFlask

为什么要有WSGI规范?
网络通信的完整流程,是这样的

  1. 先创建一个web服务器,监听端口,接收请求,并将请求路由转发给对应的应用程序。

  2. 再创建一个web应用程序,用于接收到请求,经过必要的处理,返回响应给服务器。

  3. 服务器接收响应,返回给客户端(浏览器)

试想一下,假如没有这个规范,此时我们想开发一个网页,我们需要做的就是,先搭建一个服务器,用于监听端口,接收请求,再来创建一个用于接收请求的应用程序。

听起来好像没什么问题。但是你今天开发一个网站,要写一个server,明天又要开发一个网站,又要写一个server。全中国多少web开发人员,如果按照这种模式下去,开发效率可想而知,严重浪费时间人力。

WSGI 就是来解决这个问题的,它解耦了服务器类与应用程序类。
意思就是,假如服务器类和应用程序类都严格遵守WSGI规范,那么应用程序A可以随便挑一个现成的服务器类(B,C,E都可以)来使用,而不需要其他任何的修改,只需要提供一个可以处理这些应用的请求处理类即可,不用担心兼容问题。

我们的主人公WSGI ,在服务器和应用中间承担一个“翻译官”的角色。只要应用程序符合网关接口的标准,那么服务器就只要做好服务器的角色,应用程序只要做好应用程序的作用,服务器和应用程序之间的通信全靠网关接口来协调。

. 如何实现Application?

WSGI规范 规定了,Application 必须是一个可调用的对象,它可以是函数,可以实现了__call__的类的实例对象,也可以是实现了__iter__的类对象。

不管是哪种方式的可调用对象,都要遵循两个原则

  • 必须接收environstart_response两个参数;

  • 必须返回 可迭代的对象

下面来分别看下这三个例子。

  • application是函数

 1def application(environ, start_response):
2
3   response_body = 'The request method was %s' % environ['REQUEST_METHOD']
4   status = '200 OK'
5
6   # 应答的头部是一个列表,每对键值都必须是一个 tuple。
7   response_headers = [('Content-Type', 'text/plain'),
8                       ('Content-Length', str(len(response_body)))]
9
10   # 调用服务器程序提供的 start_response,填入两个参数
11   start_response(status, response_headers)
12
13   # 返回必须是 iterable
14   return [response_body]
  • 实现了__call__的类的实例对象

 1class AppClass:
2    """这里的可调用对象就是 AppClass 的实例,使用方法类似于:
3        app = AppClass()
4        for result in app(environ, start_response):
5             do_somthing(result)
6    """
7
8    def __init__(self):
9        pass
10
11    def __call__(self, environ, start_response):
12        status = '200 OK'
13        response_headers = [('Content-type', 'text/plain')]
14        self.start(status, response_headers)
15        yield "Hello world!\n"
  • 实现了__iter__的类对象

 1class AppClass:
2    """这里的可调用对象就是 AppClass 这个类,调用它就能生成可以迭代的结果。
3        使用方法类似于:
4        for result in AppClass(env, start_response):
5             do_somthing(result)
6    """
7
8    def __init__(self, environ, start_response):
9        self.environ = environ
10        self.start = start_response
11
12    def __iter__(self):
13        status = '200 OK'
14        response_headers = [('Content-type', 'text/plain')]
15        self.start(status, response_headers)
16        yield "Hello world!\n"

. 如何实现Web Server?

上文说到,application 必须接收environstart_response两个参数。

这两个参数是什么意思?

  • environ,:是 WSGI的环境信息。

  • start_response:是响应请求的函数。

其中start_response接收两个参数,

  • status:HTTP状态,譬如:"200 OK"

  • response_headers:响应消息的头,譬如:[('Content-Type', 'text/plain')],以list的形式,每个元素是一个tuple,而一个tuple里有两个元素,一个是key,一个是value。

这两个参数(environstart_response),都是由 Web Server来定义的。

所以我们要自己实现Web Server,也必须实现这两个对象。定义完后,要调用application,将这两个参数传入。这是规定。

 1import os, sys
2
3def web_server(application):
4    # 构造environ 参数
5    environ = dict(os.environ.items())
6    environ['wsgi.input'] = sys.stdin
7    environ['wsgi.errors'] = sys.stderr
8    environ['wsgi.version'] = (1, 0)
9    environ['wsgi.multithread'] = False
10    environ['wsgi.multiprocess'] = True
11    environ['wsgi.run_once'] = True
12    environ['wsgi.url_scheme'] = 'http'
13
14    headers_set = []
15
16    # 定义响应函数
17    def start_response(status, response_headers, exc_info=None):
18        headers_set[:] = [status, response_headers]
19
20    # 调用application,并传入参数
21    result = application(environ, start_response)
22
23    # 用for循环,就解释了为什么application要返回可迭代对象
24    for data in result:
25        if data:
26            print(data)

好啦。这里只是简单举个例子。

到了现在,谁也没必要去重要写web server了,使用Python最忌讳的就是重复造轮子。那是傻。

. Web Server如何决择?

首先要明白的是,生产环境和开发环境使用的Web Server是不一样的。

就拿Django来说,其自带的Web Server有如下局限性

  • 低性能:运行起来,只有一个实例,性能可见一斑。

  • 低可用:做为服务启动,只要某个地方ERROR,服务就挂掉了。

  • 自带server只有在debug模式下可用映射静态文件,而debug模式下运行会不断留存debug信息,跑久了内存要爆。

如此看来,Django自带的server只能用于开发调试,并不适合用于生产环境。

就连Django官方也是这么说的。

It’s intended only for use while developing. (We’re in the business of making Web frameworks, not Web servers.)

意思是说,Django是一个专业的应用程序端框架,并不擅长于服务端。

果然,专业的事还是得依靠专业的软件来做。

当前市面上,已经出现了很多专业且优秀的Web Server,这里也介绍一下。

  • Gunicorn

Gunicorn(从Ruby下面的Unicorn得到的启发)应运而生:依赖Nginx的代理行为,同Nginx进行功能上的分离。由于不需要直接处理用户来的请求(都被Nginx先处理),Gunicorn不需要完成相关的功能,其内部逻辑非常简单:接受从Nginx来的动态请求,处理完之后返回给Nginx,由后者返回给用户。

由于功能定位很明确,Gunicorn得以用纯Python开发:大大缩短了开发时间的同时,性能上也不会很掉链子。同时,它也可以配合Nginx的代理之外的别的Proxy模块工作,其配置也相应比较简单。

配置上的简单,大概是它流行的最大的原因。

  • uWSGI

因为使用C语言开发,会和底层接触的更好,配置也是比较方便,目前和gunicorn两个算是部署时的唯二之选。

  • bjoern

Python WSGI界最牛逼性能的Server其中一个是bjoern,纯C,小于1000行代码,就是看不惯uWSGI的冗余自写的。

介绍完了,那么如何选择呢?

综合网友们的回答,整理如下:

  • Gunicorn,配置简单,快速上手,阻塞较多建议选择

  • uWSGI,首次配置麻烦,性能较好


标签:__,WSGI,进阶,headers,Python,start,environ,response
来源: https://blog.51cto.com/15009285/2553414

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有