web.py源码阅读(一) WSGI协议篇

WSGI协议简述

WSGI的全称是Python Web Server Gateway Interface, 看这个名称比较晦涩难懂,下面简单解释一下为什么会有WSGI这个东西。

一个网站的服务端通常分为两部分,web应用和服务器。 其中web应用通常又包括web框架和业务逻辑代码。 服务器有很多(比如uWSGI,Gunicorn等),web框架也有很多(django,flask等)。为了让框架端与服务器端解耦,即实现基于任意的框架开发的web应用可以部署在任意的web服务器上,框架与服务器之间需要制定一个规范,这个规范就是WSGI。 二者的关系大体可以用下图这个模型来表示:
这里写图片描述

web.py中WSGI的实现

  • Web框架端(Application端):

    WSGI协议规定,在web框架这一端必须定义一个可以接受两个参数的可调用对象(显然这两个参数肯定是WSGI Server传过来的),这个可调用对象可以是函数,类方法,类,以及一个包含__call__的类实例。在web.py源码中这个函数位于application.py文件下的application类里面的名为wsgi的函数,关于这个函数的具体实现细节以及参数的含义会在以后的文章中详细介绍。现在思考一个问题,WSGI协议为什么要求web框架端必须返回一个可调用对象呢?(答案是WSGI Server需要调用application端(web框架端),把request的一些信息传给application,然后application会返回response给server端)


  • WSGIServer端:

    WSGI Server端首先应该是一个服务器,其次还要实现WSGI协议。实现WSGI协议无非就是构造出需要传给web端的两个参数:environ环境变量和start_response这个函数类型的参数,然后在一次request到来的时候WSGI Server把这两个参数塞给Application端传过来的可调用对象完成调用。关于environ环境变量的构造和start_reponse函数的具体实现在后面的源码剖析中会仔细介绍,在这里先提一下,environ在web.py源码中的实现位于web/wsgiserver/init.py的HttpConnection类,而start_response这个函数的实现位于web/wsgiserver/init.py的HttpRequest类,至于WSGI Server调用Application端实现的wsgi函数则是发生在web/wsgiserver/init.py的HttpRequest类中的respond函数里面。


多说一句:Application端实现的wsgi函数会在服务器一开始启动的时候就会被注册到WSGI Server中,而具体的调用则是发生在有客户端的request到来的时候。(不理解的话可以忽略,在后面的源码详细分析中到了这个地方还是会再强调一遍)

web.py的启动流程

上面啰啰嗦嗦的算是把WSGI服务器与框架的关系介绍完了,下面打算再写一下web.py源码里面服务器的启动流程,这也是阅读源码的第一课,即当你基于web.py框架写了一个hello world程序,然后将服务run起来时,这段时间在底层源码中经历了一段怎样的故事。当然还是主要聚焦在数据的流转过程,至于每个类或者函数的具体实现会在后面的源码详细分析中一一到来。

我先贴一个hello world的程序,也是web.py的官网给出的demo事例。
这里写图片描述

接下来是一张鄙人画的并不专业的调用关系图:
这里写图片描述
下面就跟着上面这张图过一遍底层的执行过程:

        demo.py就是我们写的hello world程序,核心的代码就两行,一个是new出一个app实例,然后执行app.run()方法启动服务。好了,下面全是框架源码部分了。首先确定app.run()这个方法位于web/application.py下的application类,在这个run函数里又调用了web/wsgi.py里面的runwsgi()函数,依据是run函数中的return wsgi.runwsgi(self.wsgifunc(*middleware)),wsgifunc这个函数也是在application里面,这个函数里面还定义了wsgi函数,这个wsgi函数就是application实现了wsgi协议的那个函数,所以runwsgi接收的参数func其实就是那个wsgi函数(可调用对象)。接下来进入runwsgi函数,runwsgi里面的核心就是这句 return httpserver.runsimple(func,server_address),含义可以大概猜到就是用application传过来的wsgi函数和address这两个参数启动一个wsgi server,但是到这里我们还不清楚这个wsgi server是怎么来的。接下来进入httpserver.py这个文件一探究竟(位于web/application.py),找到runsimple函数,核心是 server = WSGIServer(server_address, func) server.start()这两行代码,到此我们清楚了,启动时的wsgi server 是一个名为WSGIServer的函数返回的实例,注意这里的WSGIServer是一个函数,不是一个类,WSGIServer这个函数位置就在runsimple函数下面。按图索骥接着进入WSGIServer这个函数,代码只有两句

 from wsgiserver import CherryPyWSGIServer
 return CherryPyWSGIServer(server_address, wsgi_app, server_name="localhost")

很清楚看到我们启动的这个server就是CherryPyWSGIServer的实例, web/wsgiserver这个包的__init__文件里有CherryPyWSGIServer这个WSGI服务器的完整实现,有兴趣的可以继续深挖一下。


2022年7月17日更新。

几年前写的文章,后面因为个人的一些原因,很惭愧博客没有坚持写下去,偶然回来看评论确实帮助到了很多同学,内心还是有一点高兴,这篇文章说的知识点并不是那些所谓的面试秒杀,高并发等对我们这些大多数日常在公司打螺丝的人来说只有面试时用到的大而虚的东西,但我想当时把这些说明白在今天看来还是有它的意义。我自己几年前也注册过一个公众号,后面没弄下去的原因是自己的知识输入确实无法支撑起持续的输出,渐渐放弃了。最近又重新申请了一个公众号,但是纯打算扯扯蛋,聊聊自己的日常生活、学习理财的体会,关于持续学习以及感兴趣的一些事情,因为纯技术的号我自己也清楚自己搞不动。我自己个人情况大体是:本科:计算机,研究生:人工智能。因为是菜狗,调参实在学不明白,毕业后目前还是在某大厂干开发大头兵,有些刚工作的同学如果需要内推,我很乐意帮忙,毕竟现在确实就业大环境不好。我最近也在思考,如果有一天自己真的被毕业了怎么办?毕竟 heros come and go,but 裁员 forever. 后来想了想一直焦虑也没啥用,保持持续学习,生活上开源节流,认真学习下理财知识,合理安排自己的工资,是自己接下来要做的事情,因为自己真的也没其它能搞钱的特长,大家也不要焦虑,一起加油。公众号名称:苇小院

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值