分享

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

 风声之家 2021-04-20
WSGI(Web 服务器网关接口)是python中所定义的Web Server和Web APP之间或框架之间的接口标准规范。当使用 Python 进行 web 开发时,要深刻理解 Django、Flask、Tornado等 web 框架,WSGI是你绕不过去的槛儿。
WSGI接口规范的目的就是规范Web服务器与Web应用之间的交互,在协议之间进行转换。
WSGI将Web组件分成三类:
  • Web服务器(Server): 监听某个端口的http服务器
  • Web应用程序(APP): 指的是可以被调用的一个对象,一般指的是一个函数 或者 包含一个__call__方法的类的实例
  • Web中间件(Middleware):处于服务器和应用中间,起到承接的作用,用Python的术语来说,中间件就类似于一个装饰器
例如:



#这是一个appdef app(environ, start_response):      return []
那么中间件通常是这样定义:



def  middleware(environ, start_response):      #这里编写中间件的代码     return app(environ, start_response)
django 整个项目实际上也是这三部分组成,我们在执行python manage.py runserver 的时候,
  1. 就首先启动了一个8000端口的http服务器(这个就是Web服务器)
  2. 然后 django里面的中间件(这个就是上述所说的Web中间件),这个是定义在 settings.py 文件的 MIDDLEWARE
  3. 最后 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. 接收两个参数environstart_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的__call__函数(这里APP是一个类) def write(data): # 这是把响应发到前端的函数 pass def data in result: # 迭代访问,把响应发到前端 write(data)
服务器程序主要做了以下的事:
  • 设定app所需要的参数(environ,start_response)
  • 调用app
  • 迭代访问app的返回结果(response body),并传给客户端
但实际上已经有很多已经封装好的WSGI Server供我们使用,只需简单的将APP与一些其他的参数绑定来创建一个Server,而这个Server会将它接收到的request传递给绑定的APP。
下面是django自带的服务器:











from wsgiref.simple_server import make_server
# 定义我们一个最简单的appdef 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()
这里我们已经自己编写了一个最基础的web框架,是不是很激动,django的本质就是这样的一种形式,是不是感觉发现了新大陆。

WSGI Middleware介绍

middleware的概念没有appllicationserver那么容易理解。假设一个符合application标准的可调用对象,它接受可调用对象作为参数,返回一个可调用对象的对象。那么对于server来说,它是一个符合标准的可调用对象,因此是application。而对于application来说,它可以调用application,因此是server。这样的可调用对象称为middleware
middleware的概念非常接近decorator
中间件对于app来说,它是一个service. 但是对于service来说,它确实一个app。文字说的不清晰,还是用代码来说比较好。



































# 这是一个标准的application objectdef index(environ, start_response):    start_response('200 OK', [('Content-Type', 'text/html')])    return ['index page']
# 这是一个标准的application objectdef hello(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return ['hello page']
# 这是一个标准的application objectdef 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) # 如果找不到,则执行默认的appfrom wsgiref.simple_server import make_server
# 创建一个服务器,IP地址为空,端口是8000,处理函数是application:httpd = make_server('', 8000, application)httpd.serve_forever()
看到没有,这个例子比上面的更加完善,利用中间件实现了路由的功能,把django最基础的功能完整的展示出来
中间件除了路由之外,还可以做很多事情,最常见的还有:
  • 负载均衡,转发用户请求 
  • 预处理 XSL 等相关数据
  • 限制请求速率,设置白名单

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多