django请求到响应到底发生了什么?

Django是一个开放源代码的Web应用框架, 由Python写成.
采用了MVC的软件设计模式, 即模型M, 视图V和控制器C.

它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的, 并于2005年7月BSD许可证下发布.

这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的.

Django的主要目标是使得开发复杂的, 数据库驱动的网站变得简单.

Django注重组件的重用性和“可插拔性”, 敏捷开发和DRY法则(Don’t Repeat Yourself).

在Django中Python被普遍使用, 甚至包括配置文件和数据模型.

Django于2008年6月17日正式成立基金会.

Django请求相应周期

流程

流程2

http server

django 内置了一个http服务器, 我们可以运行 python manage runserver # 可以指定运行ip和端口 默认为127.0.0.1:8000 启动它。(注:千万不要在生产环境使用它, 有更加优秀的部署方案如nginx..)

但是无论是哪种方式,每当启动项目,django会为我们做以下两件事:

  • 创建一个WSGIServer类是实例, 等待接收用户的请求
  • 当一个用户的请求到达时, 为用户指定一个WSGIHandler来处理本次请求并响应, 这个Handler类是整个请求的核心。

WSGI

WSGI代表Web服务器网关接口。
它是Web服务器和Python Web应用程序之间接口的规范。曾几何时,Python没有标准化的方法来连接生产级Web服务器和Web应用程序。
例如,人们使用mod_python,CGI,FastCGI等来填补Web服务器(例如Apache,Nginx等)和Web应用程序(例如Django Web应用程序)之间的空白。
为了标准化低级服务器应用程序接口,开发者们起草了一个Python增强建议(PEP),经过一些修订后,它被社区和Python专家所接受。
由于mod_python,CGI,FastCGI不是Python Web应用程序的标准接口,因此本文不讨论它们。WSGI只是低级接口的规范或标准。
WSGI有很多实现。

  • uWSGI是一个出色的生产就绪的Python Web服务器。
  • Gunicorn是另一个例子。
  • Tornado也实现了WSGI。
  • Twisted有一个内置的WSGI服务器。

甚至有几个用纯Python编写的实现。Apache有一个名为mod_wsgi的模块,它实现了WSGI。
像Nginx,Apache,其他反向代理和负载均衡器这样的Web服务器接受来自客户端(最终用户正在使用的浏览器)的初始请求,然后将请求委托给正在使用的WSGI服务器或WSGI应用程序托管容器。当WSGI服务器或容器接受请求时,它调用适当的WSGI应用程序处理函数或可调用。从现在开始,纯Python的工作开始了。
在接下来的部分中,我将讨论Django的下一步会发生什么。

可调用的WSGI应用

WSGI服务器或容器调用函数或其他可调用对象来处理最终用户请求。我们从WSGI的角度将其称为WSGI应用程序。它可以是纯函数或者可调用对象,并在其上定义call ()方法。
它接受两个参数。

  • 第一个参数是environment或environ,它将包含有关请求的所有信息和数据以及一些额外的元数据。
  • 第二个参数是函数start_response,它将用于启动响应。start_response()接受两个参数。
    第一个参数是http状态行,第二个参数是一个可迭代的请求头(headers)元组的键值对。
    WSGI应用程序callable的返回值必须是可迭代的响应数据。
    让我们用一个例子来澄清我们的概念。
    1
    2
    3
    4
    # 伪代码
    def wsgi_application(environment, start_response):
    start_response('200 OK', [('Content-Type', 'text/plain')])
    return [b'Hello, World\n', b'I am ready to be published']

注意如果在python3上运行返回的可迭代对象一定由字节(byte)字符串组成。
现在我们有足够的基础来讨论Django(打开天窗说亮化)

Django 和 WSGI

Django 提供了一个可调用的WSGI应用程序, 它的代码如下所示:

1
2
3
4
5
6
7
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "taskmaster.settings")

application = get_wsgi_application()

这里的应用程序变量包含Django提供的WSGI应用程序。
任何符合WSGI的服务器或容器都应该调用它来处理请求。

Django 引导了中…

在一切开始的时候,导入了来自Django项目的wsgi.py并且对所有需要引导的东西做了引导并初始化。
Django做的第一件事是设置它的环境,然后加载settings.py以及在settings.py中配置的其他东西。
URL配置(URLConfs)也在此阶段加载。请求处理并不会立即开始。
通常,WSGI服务器或容器在服务器启动时加载wsgi.py模块,或者至少在第一个请求到来时加载。
当请求到来时,调用与应用程序变量关联的函数或者可调用对象,到此wsgi.py模块的职责就结束了。

请求和中间件

在你的视图有机会处理请求并返回一些响应之前, 中间件就会发挥它们的作用。
django初始化项目的时候,初始和典型的中间件设置如下所示:

1
2
3
4
5
6
7
8
9
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

django 可以在没有中间件的情况下运行(可以提升一定的性能)。
当你使用django-admin startproject 命令启动项目时,
会将经常使用的中间件添加到列表中。
中间件在处理请求期间不同的生命周期和阶段有不同的对应方法, 到时候我会在另一篇文章中详细讨论中间件。
现在只需要理解, 一个请求必须先经过这些中间件列表,并且在响应的时候同样经过这些中间件。
在中间件的某些阶段, 可以停止请求, 在请求到达视图前就返回响应。

URL配置

URL配置是path()实例的一个列表(2.0前叫做url)。在其他许多框架中, 它也被叫做路由或者路由调度程序。
Django询问URL配置根据path里的定义来解析它从而了解应该调用那个视图来处理请求。
URL配置在引导阶段被加载, URL配置的路径在settings.py中由ROOT_URLCONF定义。
当然你也可以根据需要修改它, 但是设置的最合理值应该时默认值, 也就是settings.py的同级目录。
然后从django项目的其他应用程序加载其他的url配置。

视图

咨询URLConf后,如果找到匹配path()实例列表中某个模式的正确视图,则调用该视图。
视图设置为与一个或多个path()实例中的某个特定模式关联的可调用对象。
视图可以是纯函数或任何其他可调用函数。
基于类的视图定义为继承View类。
你不能直接将类设置为path()中的视图,而是必须在类上调用as_view()以获取该类的可调用。
视图函数(或View类的方法)必须至少接受一个请求参数。它是HttpRequest的一个实例。视图可调用必须返回必须是HttpResponse的实例对象的响应。
该视图是请求作为响应的最后一个站。
在这个地方你可以直接返回一些响应,或者你可以将html / xml / txt数据创建/处理责任委托给模板系统。它还可以从数据库(模型)或其他地方甚至从外部服务器检索数据。
但是视图是用来返回数据的。

返回响应

在视图生成HttpResponse对象之后,它返回到它所经过的相同路径。响应对象再次返回中间件列表,wsgi应用程序可调用,wsgi服务器/容器,然后返回面向公众的Web服务器或反向代理或负载平衡器,返回对用户的最终响应。

异常和错误

在请求/响应的过程中,任何时候都可能发生任何异常或错误。Django处理这些异常和错误,并根据异常返回响应。您可以设置自定义处理程序以向用户显示自定义结果。