怎样在你刚建立的Web服务器上运行一个Django应用和Flask应用,如何不做任何改变而适应不同的Web架构那?
在以前,选择Python web架构会受制于可用的web服务器,反之亦然。如果架构和可以协同工作,岂不更好吗?
当要把一个服务器和一个架构结合起来时,有可能会发现他们并不是被设计成协同工作的。
那么,怎么在不修改服务器和架构代码的前提下而确保可以在多个架构下运行web服务器那?答案就是:
Python Web Server Gateway Interface(简称WSGI)
WSGI允许开发者将选择web框架和web服务器分开,可以混合匹配web服务器和web框架,选择一个适合的配对,
比如,可以在Gunicorn或者Nginx/uWSGI或者Waitress上运行Django,Flask,或Pyramid,真正的混合匹配,得益于
WSGI同时支持服务器和架构:
Web服务器必须具备WSGI接口,所有的现代Python Web框架都已具备WSGI接口,它让你不对代码作修改
就能使服务器和特定的Web框架协同工作。
WSGI由Web服务器支持,而Web框架允许你选择适合自己的配对,但它同样对于服务器和框架开发者提供
便利,使他们可以专注于自己偏爱的领域和专长而不至于相互牵制。其他语言也有类似接口:java有Servlet API
,Ruby有Rack等。
当时自己学web框架和web服务器之间遵循的规范WSGI的时候真是一脸懵逼,两个之间函数调来调去,晕
晕的其实当真正知道了web框架能提供什么,web服务器需要什么,把他们之间的关系理理清楚问题就会感觉很
清晰。
下面就一起来理解下把!
首先,我们理解以下,客户端,web服务器,web框架他们之间的大概的关系脉络。
从上图中看出,先总结下没有web框架时,最简单的Client和Server之间的数据收发过程:
1.Client(浏览器)端像服务器发起链接请求,通过和Server三次握手建立连接,三次握手成功后,浏览器发起http请求,是以http协议的格式把请求发送过来。
2.web服务器读取从浏览器发送过来的http的请求,分析浏览器请求的哪个文件,把文件的内容读取出来,加载到程序中去接下来通过http的方式给浏览器(客户端)回过去。
如果是长链接,并不会进行四次挥手,而是用的同一个链接收发数据。
总结:以上是之前浏览器访问浏览器的大体的流程,收发数据,处理数据都是由web服务器自己完成。缺点就是web服务器的功能太乱了,什么都要由自己完成耦合性太强了,一个web服务器干了自己本来不应该干的工作。其实像用人一样,应该把人安排在他最擅长的岗位,什么都做反而做不好,术业有专攻,每个人都有自己的强项,并且也会为此付出自己所有的兴趣,这样才能做好 。所以,为了完成给web服务器,减压,也算是一定意义上的解耦合,web框架就要上场了。
web服务器应该做的是:接收客户端的链接,然后把最基本的东西传递到web应用程序框架中,他们之间的传递过程就要通过WSGI来完成他们之间的和谐连接。以下文章会详细讲解WSGI具体实现过程。web应用程序框架把web服务器所要的东西处理完之后,然后返回给web服务器,最后由web服务器在转发给浏览器,这样做就分工明确了,每一个模块有问题只修改其中的一个模块就行了。
小总结:一般在开发中,是不需要自己写服务器的,自己写的服务器一般功能不完善,而且bug也非常多,都是用别人写好的服务器,web服务器可能是c或者c++写的,内功不深厚者也改不动。
大体的过程我们已经了解了,下面继续理解解耦之后的过程。
解耦之后,当浏览器请求之后,web服务器要通过web应用程序框架为其提供需要给浏览器发送的header(http头信息)和body(http尾信息)。那么想要真正的让web服务器和web框架分开,完成数据的正确传递,就需要他们之间遵循某种协议。
补充:头信息和尾信息
HTTP响应分为Header和Body两部分(Body是可选项),HTTP响应中的Header最重要的几行如下:
1.HTTP/1.1 200 OK
200表示一个成功的响应,后面的OK是说明,如果返回的不是200,那么往往有其他的功能,例如:
失败的响应有404 Not Found:网页不存在
500 Internal Server Error:服务器内部出错
等等
2. Content-Type: text/html
Content-Type指示响应的内容,这里是text/html表示HTML网页。
浏览器就是依靠Content-Type来判断响应的内容是网页还是图片,是视频还是音乐。浏览器并不靠URL来判断响应的内容,所以,即使URL是http://www.baidu.com/meimei.jpg,它也不一定就是图片。
HTTP响应的Body就是HTML源码,我们在浏览器菜单栏选择“试图”,“开发者”,“查看网页源码”就可以在浏览器中直接查看HTML源码:
WSGI(web服务器网关接口)协议引出:
由web服务器调用应用程序框架中的函数,首先要让web服务器知道web应用程序框架中web服务器需要调用的函数的名字,比如在web框架中定义了一个app函数,这个函数的目的就是为了把web服务器想要的数据通过这个函数传递给web服务器。要想完成这个过程,他们之间就需要遵循WSGI协议。
WSGI过程:
由web服务器调用web应用程序框架中的函数,这个函数里边可以完成数据的读取等操作,读出来之后把数据传递给服务器。web服务器调用app函数的时候一共传两个值给这个函数,第一个值是传递一个字典,第二个值就是函数的引用,假如说在服务器里边定义了一个函数,名字叫A,在调用app函数的时候,把A当作实参传递过去(补充,一个变量接收了一个函数的引用,那么这个变量就可以直接调用这个函数)。然后由web应用程序去调用A这个函数,通过传过来的A的函数的引用,当调用这个A函数的时候把header设置好,在执行A函数之前web服务器不管以什么样的方式都要把header保存起来。当A函数执行完之后又回到了web应用程序框架,然后通过return的方式把body返回给web服务器。
到现在为止,web服务器已经有了从web应用程序框架接收到的header和body,通过稍微的处理,然后send发送,然后通过web服务器发送给浏览器。
看完了上边的理解过程还是没明白的兄弟姐妹,下面我们通过最简单的web_server和最简单的web_app(web应用程序框架):
简单的my_web应用程序框架
把web应用程序框架中函数的引用传递到web服务器,以供调用:
在web应用程序中调用的web服务器的函数,返回来头(header)信息:
在web_Server中调用web框架中的app函数来返回尾(body)信息:
以上代码分析:
头信息的传递:
web_server服务器通过调用web框架中的app(env, self.set_response_headers),把定义的字典env,和服务器中函数的引用(这个函数的引用为了接收头信息)当作实参传递给web框架中的app函数。在web服务器中,定义函数set_response_headers(self, status, headers):这个函数用两个形参来接收web框架调用这个函数的时候传递过来的实参,web框架通过调用web服务器传递过来的函数的引用,start_response(status, response_headers),把web服务器需要用的头信息当作实参传递过去,然后web服务器,通过定义了一个列表来保存web框架传递过来头信息。因为如果不用列表或者其他方法来保存传过来的头信息,信息会随着函数调用的结束而消失,为了之后继续使用,所以要把这个辗转多次得到的头信息好好保存了。
随着self.app调用的结束,通过return返回来了body信息,找个变量response_body来接收。此时服务器就有了头信息和body信息。接下来就把传过来的信息稍微整理发送给浏览器即可,这样想要发送什么样的东西只需要在web应用程序框架中添加想要发送的内容,然后通过return返回给Server服务器就行了。
希望这篇文章能给与更多人的帮助,文中有什么不足的地方,可以私信我指出,有什么不懂的地方也可以问我,我们一起交流,一起进步。