零、参考

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服务的接口规则叫做wsgiwsgi协议对于serverapplication的接口定义如下:

对于server调用规则的定义:

  1. response = application(environ, start_response)

对于application接口编码的定义:

  1. def application(environ, start_response):
  2. status = '200 OK'
  3. response_headers = [('Content-Type', 'text/plain'),]
  4. start_response(status, response_headers)
  5. return [b'hello',]

只要是遵从如上形式进一步封装serverapplication的,均称为实现了wsgi协议的server/application

python内置提供了一个wsigref模块用于提供server,但是只能用于开发测试,django框架就是使用此模块作为它的server部分,也就说,实际生产中的server部分,还需要使用其他模块来实现。

任何web框架,可能没有实现server部分或者只实现一个简单的server,但是,web框架肯定实现了application部分。application部分完成了对一次请求的全流程处理,其中各环节都可以提供丰富的功能,比如请求和响应对象的封装、model/template的实现、中间件的实现等,让我们可以更加细粒度的控制请求/响应的流程。

三、自定义一个简单的基于wsgi协议的web框架

django框架的server部分由python内置的wsgiref模块提供,我们只需要编写application应用程序部分。

  1. from wsgiref.simple_server import make_server
  2. def app(environ, start_response): # wsgi协议规定的application部分的编码形式,可在此基础上扩展
  3. status = '200 OK'
  4. respones_headers = []
  5. start_response(status, response_headers)
  6. return [b'hello',]
  7. if __name__ == '__main__':
  8. httpd = make_server('127.0.0.1', 8080, app)
  9. httpd.serve_forever()

用以下图示表示简单的web请求流程架构(伪代码)

web服务器就像是一颗心脏不停的跳动,驱动整个web系统为用户提供http访问服务,并调用application返回响应

四、django中的server实现

django使用的底层server模块是基于python内置的wsgiref模块中的simple_server,每次django的启动都会执行如下run函数。run函数中会执行serve_forever,此步骤将会启动socket_server的无限循环,此时就可以循环提供请求服务,每次客户端请求到来,服务端就执行django提供的application模块。

djangoserver的启动----django.core.servers.basehttp.py

  1. """
  2. HTTP server that implements the Python WSGI protocol (PEP 333, rev 1.21).
  3. Based on wsgiref.simple_server which is part of the standard library since 2.5.
  4. This is a simple server for use in testing or debugging Django apps. It hasn't
  5. been reviewed for security issues. DON'T USE IT FOR PRODUCTION USE!
  6. """
  7. def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
  8. server_address = (addr, port)
  9. if threading:
  10. httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
  11. else:
  12. httpd_cls = server_cls
  13. httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
  14. if threading:
  15. # ThreadingMixIn.daemon_threads indicates how threads will behave on an
  16. # abrupt shutdown; like quitting the server by the user or restarting
  17. # by the auto-reloader. True means the server will not wait for thread
  18. # termination before it quits. This will make auto-reloader faster
  19. # and will prevent the need to kill the server manually if a thread
  20. # isn't terminating correctly.
  21. httpd.daemon_threads = True
  22. httpd.set_app(wsgi_handler)
  23. httpd.serve_forever()

底层无限循环将作为web服务的主要驱动----socektserver.py

  1. def serve_forever(self, poll_interval=0.5):
  2. """Handle one request at a time until shutdown.
  3. Polls for shutdown every poll_interval seconds. Ignores
  4. self.timeout. If you need to do periodic tasks, do them in
  5. another thread.
  6. """
  7. self.__is_shut_down.clear()
  8. try:
  9. # XXX: Consider using another file descriptor or connecting to the
  10. # socket to wake this up instead of polling. Polling reduces our
  11. # responsiveness to a shutdown request and wastes cpu at all other
  12. # times.
  13. with _ServerSelector() as selector:
  14. selector.register(self, selectors.EVENT_READ)
  15. while not self.__shutdown_request:
  16. ready = selector.select(poll_interval)
  17. if ready:
  18. self._handle_request_noblock()
  19. self.service_actions()
  20. finally:
  21. self.__shutdown_request = False
  22. self.__is_shut_down.set()

server对于application的调用----wsgiref.handlers.py

  1. def run(self, application):
  2. """Invoke the application"""
  3. # Note to self: don't move the close()! Asynchronous servers shouldn't
  4. # call close() from finish_response(), so if you close() anywhere but
  5. # the double-error branch here, you'll break asynchronous servers by
  6. # prematurely closing. Async servers must return from 'run()' without
  7. # closing if there might still be output to iterate over.
  8. try:
  9. self.setup_environ()
  10. self.result = application(self.environ, self.start_response)
  11. self.finish_response()
  12. except:
  13. try:
  14. self.handle_error()
  15. except:
  16. # If we get an error handling an error, just give up already!
  17. self.close()
  18. raise # ...and let the actual server figure it out.

五、django中的application实现

djangoapplication模块是通过WSGIHandler的一个实例来提供的,此实例可以被call,然后根据wsgi的接口规则传入environstart_response。所以本质上,django就是使用的内置python提供的wsgiref.simple_server再对application进行丰富的封装。大部分的django编码工作都在application部分。

application的编码定义部分----django.core.handlers.wsgi.py

  1. class WSGIHandler(base.BaseHandler):
  2. request_class = WSGIRequest
  3. def __init__(self, *args, **kwargs):
  4. super().__init__(*args, **kwargs)
  5. self.load_middleware()
  6. def __call__(self, environ, start_response):
  7. set_script_prefix(get_script_name(environ))
  8. signals.request_started.send(sender=self.__class__, environ=environ)
  9. request = self.request_class(environ)
  10. response = self.get_response(request)
  11. response._handler_class = self.__class__
  12. status = '%d %s' % (response.status_code, response.reason_phrase)
  13. response_headers = list(response.items())
  14. for c in response.cookies.values():
  15. response_headers.append(('Set-Cookie', c.output(header='')))
  16. start_response(status, response_headers)
  17. if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
  18. response = environ['wsgi.file_wrapper'](response.file_to_stream)
  19. return response

六、django的底层调用链

七、总结

web服务是基于socket的高层服务,所以web服务必须含有web服务器这一模块。

web服务需要动态渲染数据,需要中间件来丰富功能,需要封装和解析来处理数据,所以web服务必须含有web应用程序这一模块。

web框架是一种工具集,封装了各种功能的底层代码,提供给我们方便开发的接口。但不论是哪一种框架,它们的底层原理基本都是一致的。

应该深入学习、研究一个web框架,精通一门框架的实现原理和设计理念。

django框架--底层架构的更多相关文章

  1. [Python自学] day-18 (2) (MTV架构、Django框架、模板语言)

    一.实现一个简单的Web服务器 使用Python标准库提供的独立WSGI服务器来实现MVC架构. 首先,实现一个简单的Web服务器: from wsgiref.simple_server import ...

  2. Django框架架构总览

    Django框架架构总览 理解Django是如何运作的 条目创建于 2013-08-14     1464 views     服务器君一共花费 15.204 ms 进行了 4 次数据库查询,努力地为 ...

  3. WEB框架-Django框架学习-预备知识

    今日份整理,终于开始整个阶段学习的后期了,今日开始学习Django的框架,加油,你是最胖的! 1.web基础知识 1.1 web应用 Web应用程序是一种可以通过Web访问的应用程序,程序的最大好处是 ...

  4. Django框架理解和使用常见问题

    1.什么是中间件? 中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出. 中间件一般做认证或批量请求处理,django中的中间 ...

  5. 第六模块:WEB框架开发 第1章·Django框架开发1~50

    01-Django基础介绍 02-Web应用程序1 03-Web应用程序2 04-http请求协议1 05-http请求协议2 06-http协议之响应协议 07-wsgire模块1 08-wsgir ...

  6. Django框架的理解和使用的常见问题

    1.什么是中间件? 中间件是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出. 中间件一般做认证或批量请求处理,django中的中间 ...

  7. django(django框架了解,http协议)

    Django框架 学习目的: 完成web应用的编写 django的作用: 0.业务逻辑分发(路由分发) 1.业务逻辑实现: 业务逻辑根据分发来完成具体的事,再根据具体事的需求,和页面或数据库交互,返回 ...

  8. Django框架3——模型

    Django数据库层解决的问题 在本例的视图中,使用了pymysql 类库来连接 MySQL 数据库,取回一些记录,将它们提供给模板以显示一个网页: from django.shortcuts imp ...

  9. MVC其实很简单(Django框架)

    Django框架MVC其实很简单 让我们来研究一个简单的例子,通过该实例,你可以分辨出,通过Web框架来实现的功能与之前的方式有何不同. 下面就是通过使用Django来完成以上功能的例子: 首先,我们 ...

随机推荐

  1. Linux服务器部署系列之一—Apache篇(下)

    接上篇 linux服务器部署系列之一—Apache篇(上)    四.管理日志文件 Apache日志分为访问日志和错误日志两种: 1)访问日志 用于记录客户端的访问信息,文件名默认为access_lo ...

  2. IntelliJ IDEA 2017版 spring-boot 报错Consider defining a bean of type 'xxx' in your configuration问题解决方案

    问题分析: 通过问题的英文可知,这个错误是service的bean注入失败,那么为什么会产生这个问题呢? 主要是框架的Application产生的,所以我们建立项目的时候,要保证项目中的类跟Appli ...

  3. UVa 10269 Adventure of Super Mario (Floyd + DP + BFS)

    题意:有A个村庄,B个城市,m条边,从起点到终点,找一条最短路径.但是,有一种工具可以使人不费力的移动L个长度,但始末点必须是城市或村庄.这种工具有k个,每个只能使用一次,并且在城市内部不可使用,但在 ...

  4. 深度linux没有ll等命令的解决办法

    编辑~/.bashrc, 添加alias 如下 vim ~/.bashrc 设置别名. 添加如下行 alias ll='ls -alF' alias la='ls -A' alias vi='vim' ...

  5. (转载)从Java角度理解Angular之入门篇:npm, yarn, Angular CLI

    本系列从Java程序员的角度,带大家理解前端Angular框架. 本文是入门篇.笔者认为亲自动手写代码做实验,是最有效最扎实的学习途径,而搭建开发环境是学习一门新技术最需要先学会的技能,是入门的前提. ...

  6. volatile 类型修饰符

    volatile 类型修饰符 1.解释 就像大家更熟悉的const一样,volatile是一个类型修饰符(type specifier).它是被设计用来修饰被不同线程访问和修改的变量.如果不加入vol ...

  7. 【spfa训练】HDU4725 (层级建图)

    HDU4725 题目大意:一些节点分布在不同的层上,已知相邻的层可以往来距离为c,在给你一些已知的边,问你点1-n的最短路 分析:越往后做,越觉得最短路的考点已经不是spfa算法还是dijkscar算 ...

  8. Nonsense Alphabet

    Nonsense Alphabet A was an ant Who seldom stood still, And who made a nice house In the side of a hi ...

  9. sqlserver 实现数据变动触发信息

    1.建立存储过程,功能是动态写入文件中信息,可以在触发器或存储过程调用. SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO create proc [d ...

  10. 我要总结基本书 .net稍微有些深度的书籍看看

    1. 你必须知道的.NET 2. C# in depth 3.C#并发编程经典实例 4.ASP.NET MVC 4框架揭秘 5.NET最佳实践 6..NET探秘 .NET安全编程 .NET企业服务框架 ...