详解WSGI
如上图所示,wsgi一端连接web服务器(http服务器),另一端连接应用。目前已经有很多的web框架,如flask、webpy,用户只要简单配置一些路由信息,就能开发出一个web应用。后文中的web框架就等同于应用(application)
一、什么是wsgi
(1)、RESTful只是设计风格而不是标准,而WSGI(Web Server Gateway Interface,Web 服务器网关接口)则是Python语言中所定义的Web服务器和Web应用程序之间或框架之间的通用接口标准。
(2)、WSGI就是一座桥梁,桥梁的一端称为服务端或网关端,另一端称为应用端或者框架端,WSGI的作用就是在协议之间进行转化。WSGI将Web组件分成了三类:Web 服务器(WSGI Server)、Web中间件(WSGI Middleware)与Web应用程序(WSGI Application)。
应用:指的是可以被调用的一个对象,一般指的是包含一个__call__方法(实例可以当作函数一般调用)的对象。
服务器:指的是实现了调用应用的部分。
中间件:处于服务器和应用两侧,起粘合作用,具体包括:请求处理、environ处理。
(3)、Web Server接收HTTP请求,封装一系列环境变量,按照WSGI接口标准调用注册的WSGI Application,最后将响应返回给客户端。
(4)、Web应用的本质:
1)、浏览器发送HTTP请求
2)、服务器接收到请求,生成HTML文档
3)、服务器把HTML文档作为HTTP响应的Body发送给浏览器
4)、浏览器收到HTTP响应,从HTTP Body取出HTML文档进行显示
接受HTTP请求、解析HTTP请求、发送HTTP响应都是重复的苦力活,如果我们自己来写这些底层代码,还没开始写HTML,先要花半把个月研读HTTP规范。所以底层的代码应该由专门的服务器软件实现,我们用python专注于生成HTML文档。
因为我们不想要接触TCP连接、HTTP原始请求和响应格式。所以需要一个统一的接口,专心用python编写Web业务。
这个接口就是 WSGI:(Web 服务器网关接口)。
https://blog.csdn.net/li_101357/article/details/52748686和https://my.oschina.net/crooner/blog/609030, 这些网页讲wsgi讲的不错。
比如上面的图中,如果从客户端的浏览器发送一个请求到nginx服务器,如果是静态资源,那么nginx服务器可能就只需直接返回即可,但是如果浏览器发送的是一个需要动态资源的请求,那么就是通过nginx服务器传到wsgi,再通过wsgi讲请求发送到应用程序框架,比如flask,应用程序框架讲数据准备好做成响应的head和body,通过wsgi回传给nginx,最后由服务器进行封装整理发送给客户端浏览器。
了解了HTTP协议和HTML文档,我们其实就明白了一个Web应用的本质就是:
-
浏览器发送一个HTTP请求;
-
服务器收到请求,生成一个HTML文档;
-
服务器把HTML文档作为HTTP响应的Body发送给浏览器;
-
浏览器收到HTTP响应,从HTTP Body取出HTML文档并显示。
所以,最简单的Web应用就是先把HTML用文件保存好,用一个现成的HTTP服务器软件,接收用户请求,从文件中读取HTML,返回。Apache、Nginx、Lighttpd等这些常见的静态服务器就是干这件事情的。
如果要动态生成HTML,就需要把上述步骤自己来实现。不过,接受HTTP请求、解析HTTP请求、发送HTTP响应都是苦力活,如果我们自己来写这些底层代码,还没开始写动态HTML呢,就得花个把月去读HTTP规范。
正确的做法是底层代码由专门的服务器软件实现,我们用Python专注于生成HTML文档。因为我们不希望接触到TCP连接、HTTP原始请求和响应格式,所以,需要一个统一的接口,让我们专心用Python编写Web业务。
1 def application(environ, start_response): 2 start_response('200 OK', [('Content-Type', 'text/html')]) # 这一步就是相当于上图中的第3步,这个start_response由web服务器提供 3 return '<h1>Hello, web!</h1>' # 这一步就是相当于上图中的第6步
上面代码是一个最简单的应用程序,
上面的application()
函数就是符合WSGI标准的一个HTTP处理函数,它接收两个参数:
-
environ:一个包含所有HTTP请求信息的
dict
对象; -
start_response:一个发送HTTP响应的函数。
在application()
函数中,调用:
1 start_response('200 OK', [('Content-Type', 'text/html')])
就发送了HTTP响应的Header,注意Header只能发送一次,也就是只能调用一次start_response()
函数。start_response()
函数接收两个参数,一个是HTTP响应码,一个是一组list
表示的HTTP Header,每个Header用一个包含两个str
的tuple
表示。
通常情况下,都应该把 1 Content-Type 头发送给浏览器。其他很多常用的HTTP Header也应该发送。
然后,函数的返回值
'<h1>Hello, web!</h1>'
将作为HTTP响应的Body发送给浏览器。
整个application()
函数本身没有涉及到任何解析HTTP的部分,也就是说,底层代码不需要我们自己编写,我们只负责在更高层次上考虑如何响应请求就可以了。
不过,等等,这个application()
函数怎么调用?如果我们自己调用,两个参数environ
和start_response
我们没法提供,返回的str
也没法发给浏览器。
所以application()
函数必须由WSGI服务器来调用。有很多符合WSGI规范的服务器,我们可以挑选一个来用。但是现在,我们只想尽快测试一下我们编写的application()
函数真的可以把HTML输出到浏览器,所以,要赶紧找一个最简单的WSGI服务器,把我们的Web应用程序跑起来。
好消息是Python内置了一个WSGI服务器,这个模块叫wsgiref,它是用纯Python编写的WSGI服务器的参考实现。所谓“参考实现”是指该实现完全符合WSGI标准,但是不考虑任何运行效率,仅供开发和测试使用。
通过这个网站https://www.liaoxuefeng.com/wiki/897692888725344/923057057214336可以更好的了解web框架的用处。