django框架--底层架构
目录
- 零、参考
- 一、对于web服务的理解
- 二、对于wsgi协议的理解
- 三、自定义一个简单的基于wsgi协议的web框架
- 四、django中的server实现
- 五、django中的application实现
- 六、django的底层调用链
- 七、总结
零、参考
https://www.jianshu.com/p/679dee0a4193
https://www.letiantian.me/2015-09-10-understand-python-wsgi/
一、对于web服务的理解
web
服务应该至少包含两个模块:web
服务器和web
应用程序,两个模块在功能和代码上解耦。web
服务器负责处理socket
调用、http
数据解析和封装等底层操作。web
应用程序负责业务处理、数据增删改查、页面渲染/生成等高层操作。web
服务器一旦接收到http
请求,经过自身的解析后就会调用web
应用程序来处理业务逻辑,并得到web
应用程序的返回值,再经过自身的封装发送给客户端。
二、对于wsgi协议的理解
在web
服务器和web
应用程序之间需要定义一个接口规则,这也叫协议,用于明确两者之间以什么样的形式交互数据。即:web
服务器应该以什么样的形式调用web应用程序,而web
应用程序又应该定义成什么形式。
python
下规定的web
服务的接口规则叫做wsgi
,wsgi
协议对于server
和application
的接口定义如下:
对于server
调用规则的定义:
response = application(environ, start_response)
对于application
接口编码的定义:
def application(environ, start_response): status = '200 OK' response_headers = [('Content-Type', 'text/plain'),] start_response(status, response_headers) return [b'hello',]
只要是遵从如上形式进一步封装server
和application
的,均称为实现了wsgi
协议的server/application
。
python
内置提供了一个wsigref
模块用于提供server
,但是只能用于开发测试,django
框架就是使用此模块作为它的server
部分,也就说,实际生产中的server
部分,还需要使用其他模块来实现。
任何web
框架,可能没有实现server
部分或者只实现一个简单的server
,但是,web
框架肯定实现了application
部分。application
部分完成了对一次请求的全流程处理,其中各环节都可以提供丰富的功能,比如请求和响应对象的封装、model/template
的实现、中间件的实现等,让我们可以更加细粒度的控制请求/响应的流程。
三、自定义一个简单的基于wsgi协议的web框架
django
框架的server
部分由python
内置的wsgiref
模块提供,我们只需要编写application
应用程序部分。
from wsgiref.simple_server import make_server def app(environ, start_response): # wsgi协议规定的application部分的编码形式,可在此基础上扩展 status = '200 OK' respones_headers = [] start_response(status, response_headers) return [b'hello',] if __name__ == '__main__': httpd = make_server('127.0.0.1', 8080, app) httpd.serve_forever()
四、django中的server实现
django
使用的底层server
模块是基于python
内置的wsgiref
模块中的simple_server
,每次django
的启动都会执行如下run
函数。run
函数中会执行serve_forever
,此步骤将会启动socket_server
的无限循环,此时就可以循环提供请求服务,每次客户端请求到来,服务端就执行django
提供的application
模块。
django
中server
的启动----django.core.servers.basehttp.py
""" HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21). Based on wsgiref.simple_server which is part of the standard library since 2.5. This is a simple server for use in testing or debugging Django apps. It hasn't been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE! """ def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer): server_address = (addr, port) if threading: httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {}) else: httpd_cls = server_cls httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6) if threading: # ThreadingMixIn.daemon_threads indicates how threads will behave on an # abrupt shutdown; like quitting the server by the user or restarting # by the auto-reloader. True means the server will not wait for thread # termination before it quits. This will make auto-reloader faster # and will prevent the need to kill the server manually if a thread # isn't terminating correctly. httpd.daemon_threads = True httpd.set_app(wsgi_handler) httpd.serve_forever()
底层无限循环将作为web
服务的主要驱动----socektserver.py
def serve_forever(self, poll_interval=0.5): """Handle one request at a time until shutdown. Polls for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread. """ self.__is_shut_down.clear() try: # XXX: Consider using another file descriptor or connecting to the # socket to wake this up instead of polling. Polling reduces our # responsiveness to a shutdown request and wastes cpu at all other # times. with _ServerSelector() as selector: selector.register(self, selectors.EVENT_READ) while not self.__shutdown_request: ready = selector.select(poll_interval) if ready: self._handle_request_noblock() self.service_actions() finally: self.__shutdown_request = False self.__is_shut_down.set()
server
对于application
的调用----wsgiref.handlers.py
def run(self, application): """Invoke the application""" # Note to self: don't move the close()! Asynchronous servers shouldn't # call close() from finish_response(), so if you close() anywhere but # the double-error branch here, you'll break asynchronous servers by # prematurely closing. Async servers must return from 'run()' without # closing if there might still be output to iterate over. try: self.setup_environ() self.result = application(self.environ, self.start_response) self.finish_response() except: try: self.handle_error() except: # If we get an error handling an error, just give up already! self.close() raise # ...and let the actual server figure it out.
五、django中的application实现
django
的application
模块是通过WSGIHandler
的一个实例来提供的,此实例可以被call
,然后根据wsgi
的接口规则传入environ
和start_response
。所以本质上,django
就是使用的内置python
提供的wsgiref.simple_server
再对application
进行丰富的封装。大部分的django
编码工作都在application
部分。
application
的编码定义部分----django.core.handlers.wsgi.py
class WSGIHandler(base.BaseHandler): request_class = WSGIRequest def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.load_middleware() def __call__(self, environ, start_response): set_script_prefix(get_script_name(environ)) signals.request_started.send(sender=self.__class__, environ=environ) request = self.request_class(environ) response = self.get_response(request) response._handler_class = self.__class__ status = '%d %s' % (response.status_code, response.reason_phrase) response_headers = list(response.items()) for c in response.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'): response = environ['wsgi.file_wrapper'](response.file_to_stream) return response
六、django的底层调用链
七、总结
web
服务是基于socket
的高层服务,所以web
服务必须含有web
服务器这一模块。web
服务需要动态渲染数据,需要中间件来丰富功能,需要封装和解析来处理数据,所以web
服务必须含有web
应用程序这一模块。web
框架是一种工具集,封装了各种功能的底层代码,提供给我们方便开发的接口。但不论是哪一种框架,它们的底层原理基本都是一致的。
应该深入学习、研究一个web
框架,精通一门框架的实现原理和设计理念。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
@程序员,拒绝无聊的代码面试!
要判断一个人是不是优秀的程序员,不一定非要看他的代码。 过去十多年里,我面试了许多工程师。在那段时间里,我总结了一系列的方法,可以在不看代码的情况下快速准确地评价一名开发人员。 而我现在认为,这些方法不仅可行,而且客观上比代码面试更好。 什么是“代码面试”? “代码面试”指所有直接测试候选人的技能,或审查他们编写的代码或伪代码的方法。这些方法包括: 审查代码片段,或GitHub的个人页面; 编程测试(Codility等); 编程挑战,或在个人时间里自由完成的题目; 现场编程,或结对编程; 在白板上实现算法。 说到这里,也给大家推荐一个架构交流学习群:835544715,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工作和遇到技术瓶颈的码友,在这个群里会有你需要的内容。 代码面试的目的 这些方法的出现绝非偶然,而是为了取代那些更差的面试手段,比如: 脑筋急转弯:一架波音747中能装多少个网球? 咬文嚼字:Java中接口和子...
- 下一篇
高可用 Redis 服务架构分析与搭建
基于内存的Redis应该是目前各种web开发业务中最为常用的key-value数据库了,我们经常在业务中用其存储用户登陆态(Session存储),加速一些热数据的查询(相比较mysql而言,速度有数量级的提升),做简单的消息队列(LPUSH和BRPOP)、订阅发布(PUB/SUB)系统等等。 规模比较大的互联网公司,一般都会有专门的团队,将Redis存储以基础服务的形式提供给各个业务调用。 不过任何一个基础服务的提供方,都会被调用方问起的一个问题是:你的服务是否具有高可用性?最好不要因为你的服务经常出问题,导致我这边的业务跟着遭殃。最近我所在的项目中也自己搭了一套小型的“高可用”Redis服务,在此做一下自己的总结和思考。 首先我们要定义一下对于Redis服务来说怎样才算是高可用,即在各种出现异常的情况下,依然可以正常提供服务。或者宽松一些,出现异常的情况下,只经过很短暂的时间即可恢复正常服务。所谓异常,应该至少包含了以下几种可能性: 【异常1】某个节点服务器的某个进程突然down掉(例如某开发手残,把一台服务器的redis-server进程kill了) 【异常2】某台节点服务器dow...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- CentOS6,CentOS7官方镜像安装Oracle11G
- Windows10,CentOS7,CentOS8安装Nodejs环境
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题