年薪20万Python工程师进阶(3):Python开发之理解WSGI(上)

本文目录


什么是WSGI?

如何实现Application?

如何实现Web Server?

Web Server如何决择?

. 什么是WSGI?

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

那么这个规范是什么?

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

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

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

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

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

Gateway Interface:网关接口

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

常见的web server有uWSGI、Gunicorn

常见的 Gateway Interface 有CGI, WSGI

常见的application框架有 Django、Flask

为什么要有WSGI规范?

网络通信的完整流程,是这样的

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

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

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

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

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

WSGI 就是来解决这个问题的,它解耦了服务器类与应用程序类。

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

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

. 如何实现Application?

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

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

必须接收environ, start_response两个参数;

必须返回 可迭代的对象。

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

application是函数

1defapplication(environ, start_response):

2

3response_body ='The request method was %s'% environ['REQUEST_METHOD']

4status ='200 OK'

5

6# 应答的头部是一个列表,每对键值都必须是一个 tuple。

7response_headers = [('Content-Type','text/plain'),

8('Content-Length', str(len(response_body)))]

9

10# 调用服务器程序提供的 start_response,填入两个参数

11start_response(status, response_headers)

12

13# 返回必须是 iterable

14return[response_body]

实现了__call__的类的实例对象

1classAppClass:

2"""这里的可调用对象就是 AppClass 的实例,使用方法类似于:

3app = AppClass()

4for result in app(environ, start_response):

5do_somthing(result)

6"""

7

8def__init__(self):

9pass

10

11def__call__(self, environ, start_response):

12status ='200 OK'

13response_headers = [('Content-type','text/plain')]

14self.start(status, response_headers)

15yield"Hello world!\n"

实现了__iter__的类对象

1classAppClass:

2"""这里的可调用对象就是 AppClass 这个类,调用它就能生成可以迭代的结果。

3使用方法类似于:

4for result in AppClass(env, start_response):

5do_somthing(result)

6"""

7

8def__init__(self, environ, start_response):

9self.environ = environ

10self.start = start_response

11

12def__iter__(self):

13status ='200 OK'

14response_headers = [('Content-type','text/plain')]

15self.start(status, response_headers)

16yield"Hello world!\n"

. 如何实现Web Server?

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

这两个参数是什么意思?

environ,:是 WSGI的环境信息。

start_response:是响应请求的函数。

其中start_response接收两个参数,

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

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

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

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

1importos, sys

2

3defweb_server(application):

4# 构造environ 参数

5environ = dict(os.environ.items())

6environ['wsgi.input'] = sys.stdin

7environ['wsgi.errors'] = sys.stderr

8environ['wsgi.version'] = (1,0)

9environ['wsgi.multithread'] =False

10environ['wsgi.multiprocess'] =True

11environ['wsgi.run_once'] =True

12environ['wsgi.url_scheme'] ='http'

13

14headers_set = []

15

16# 定义响应函数

17defstart_response(status, response_headers, exc_info=None):

18headers_set[:] = [status, response_headers]

19

20# 调用application,并传入参数

21result = application(environ, start_response)

22

23# 用for循环,就解释了为什么application要返回可迭代对象

24fordatainresult:

25ifdata:

26print(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,首次配置麻烦,性能较好

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容