django进阶---从WSGI的介绍到django原理解析

     WSGI(Web 服务器网关接口)是python中所定义的Web Server和Web APP之间或框架之间的接口标准规范。当使用 Python 进行 web 开发时,要深刻理解 Django、Flask、Tornado等 web 框架,WSGI是你绕不过去的槛儿。
     WSGI接口规范的目的就是规范Web服务器与Web应用之间的交互,在协议之间进行转换。
     WSGI将Web组件分成三类:
     1. Web服务器(Server): 监听某个端口的http服务器
     2. Web中间件(Middleware): 处于服务器和应用中间,起到承接的作用,用python的术语来说,中间件就类似于一个装饰器
例如: def app(environ, start_response):   这是一个app
              return []
 
那么中间件通常是这样定义:
         def  middleware(environ, start_response):
                //这里编写中间件的代码
                return app(environ, start_response)
 
     3. Web应用程序(APP): 指的是可以被调用的一个对象,一般指的是一个函数 或者 包含一个__call__方法的类的实例
 
django 整个项目实际上也是这三部分组成,我们在执行python manage.py runserver 的时候,
就首先启动了一个8000端口的http服务器(这个就是Web服务器)
然后 django里面的中间件(这个就是上述所说的Web中间件),这个是定义在 settings.py 文件的 MIDDLEWARE
最后 django加载里面的app(这个就是上述所说的Web应用程序),这个是定义在 settings.py 文件的 INSTALLED_APPS

什么是WSGI APP:

WSGI APP是一个可调用的对象(callable object),常用的可调用的对象有三种:

1.一个函数或者类的方法:

 

def app(environ, start_response):   这是一个app
      return []
 
2.一个实现__call__()方法的类的实例:

 

class app:

    def __call__(environ, start_response):

         start_response('200 OK', [('Content-Type', 'text/html')])

         return []   

      

这个可调用的对象有几点需要说明一下:

1. 接收两个参数environ和start_response:
environ是一个字典,里面储存了HTTP request的所有内容。在django里面,通常会把environ 封装成为一个request。

start_response是一个WSGI Server(http 服务器)传递过来的函数,用于将response header,  status传递给Server。

start_response(status, headers), 它的作用是返回状态码 以及 头部信息, status必须是一个字符串,格式是 “状态码 + 说明”。

headers 是一个数组,按照 [(key, value), (key, value) ] 这样的格式来组织。

2.它需要返回一个可迭代的值,用于将response body传递给Server。

["hello world", "baby"]

 

WSGI Server

WSGI Server可以理解为就是一个实现了wsgi协议的http服务器,使用wsgi协议的方式来调用WSGI APP。

通常来说,它由两部分组成:
1. http 服务器: 这里具体的代码就不写了,大概就是
 
socket = eventlet.listen(('localhost', '8000'), backlog = 10)  定义一个wsgi http服务器
server = eventlet.spawn(event.wsgi.server, socket, app) 把service 和 app进行绑定
                                  
2. 调用app的主方法:
def run(application): #服务器程序调用应用程序

    environ = {}#设定参数
def start_response(status, headers): #设定状态和头部参数的回调函数 pass result = application(environ, start_response)#调用APP def write(data): # 这是把响应发到前端的函数 pass def data in result: # 迭代访问,把响应发到前端 write(data)
服务器程序主要做了以下的事:
  1. 设定app所需要的参数(environ,start_response)
  2. 调用app
  3. 迭代访问app的返回结果(response body),并传给客户端

但实际上已经有很多已经封装好的WSGI Server供我们使用,只需简单的将APP与一些其他的参数绑定来创建一个Server
而这个Server会将它接收到的request传递给绑定的APP。

下面是django自带的服务器:

from wsgiref.simple_server import make_server

# 定义我们一个最简单的app
def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [b'<h1>Hello, web!</h1>']

# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
print('Serving HTTP on port 8000...')  # 开始监听HTTP请求:
httpd.serve_forever()

  


看, 我们已经自己编写了一个最基础的django,是不是很激动,django的本质就是这样的一种形式,是不是感觉发现了新大陆。

WSGI Middleware

middleware的概念没有appllication和server那么容易理解。
假设一个符合application标准的可调用对象,它接受可调用对象作为参数,返回一个可调用对象的对象。
那么对于server来说,它是一个符合标准的可调用对象,因此是application。
而对于application来说,它可以调用application,因此是server。
这样的可调用对象称为middleware。

middleware的概念非常接近decorator。

中间件对于app来说,它是一个service. 但是对于service来说,它确实一个app。文字说的不清晰,还是用代码来说比较好。

 

# 这是一个标准的application object
def index(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['index page']

# 这是一个标准的application object
def hello(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['hello page']

# 这是一个标准的application object
def not_found(environ, start_response):
    start_response('404 NOT FOUND', [('Content-Type', 'text/plain')])
    return ['Not Found Page']
 
###上面我们定义了三个app
### 然后我们定义一个中间件 middleware, 看到没有,这个中间件的形式是跟app是一样的
def application(environ, start_response):
    path = environ.get('PATH_INFO', '').lstrip('/')  #这句代码是获取url
    
     urls = [  # 这里定义路由
         ('index', index),
         ('hello', hello)
     ]
     
     for item in urls:  # 这里根据路由,执行不同的app
          if item[0] == path:
               app = item[1]
               return app(environ, start_response)
     else:     return not_found(environ, start_response) # 如果找不到,则执行默认的app
from wsgiref.simple_server import make_server

# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:
httpd = make_server('', 8000, application)
httpd.serve_forever()

  

 
看到没有,这个例子比上面的更加完善,利用中间件实现了路由的功能,把django最基础的功能完整的展示出来
 
中间件除了路由之外,还可以做很多事情,最常见的还有:
• 负载均衡,转发用户请求
• 预处理 XSL 等相关数据
• 限制请求速率,设置白名单
等等等
 

posted on 2020-04-27 11:41  摩登海贼  阅读(1823)  评论(0编辑  收藏  举报