深入了解WSGI与Werkzeug

图片[1]-深入了解WSGI与Werkzeug-uusu优素-乐高,模型,3d打印,编程

在介绍Werkzeug之前,先介绍一下 WSGI(Python Web Server Gateway Interface),它为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。

这是一个规范,描述了web server如何与web application交互、web application如何处理请求,该规范的具体描述在PEP3333,强烈推荐先阅读 PEP3333 再回头来阅读本文。

WSGI 分为两个部分:

  • Server/Gateway: 即是HTTP Server, 负责从客户端(Nnginx、apache、IIS)接收请求,将 request 转发给 application, 并将 application(可能是个Flask应用) 返回的response 返回给客户端
  • Application/Framework: 一个python web 应用或 web 框架接收由 server 转发的request,处理请求,并将处理结果返回给 server

可以通过下面两张图片来梳理一下它们之间的调用关系:

01.jpg

02.jpg

先从一份示例代码理解:

defapplication(environ,start_response):
start_response('200OK',[('Content-Type','text/plain')])
return['HelloWorld!']

一个最基本的 WSGI 应用就是如上所示,定义了一个 application 函数(callable object),callable object(可调用对象) 包括: 一个函数、方法、类或一个实现了__call__的实例都可以用作应用程序对象。这个函数接受两个参数,分别是environ和start_response。

  • environ是一个字典包含了CGI中的环境变量
  • start_response也是一个callable,接受两个必须的参数,status(HTTP状态)和response_headers(响应消息的头)

通过回调函数(start_response)将响应状态和响应头返回给 server,同时返回响应正文(response body),响应正文是可迭代的、并包含了多个字符串。

Werkzeug


werkzeug 提供了 python web WSGI 开发相关的功能:

  • 路由处理:如何根据请求 URL 找到对应的视图函数
  • request 和 response 封装: 提供更好的方式处理request和生成response对象
  • 自带的 WSGI server: 测试环境运行WSGI应用

下面使用 Werkzeug 来实现一个简单的WSGI应用:

fromwerkzeug.wrappersimportRequest,Response
defapplication(environ,start_response):
request=Request(environ)
text='Hello%s!'%request.args.get('name','World')
response=Response(text,mimetype='text/plain')
returnresponse(environ,start_response)

如上代码所示,请求数据需要环境对象,Werkzeug允许你以一个轻松的方式访问数据。响应对象是一个 WSGI 应用,提供了更好的方法来创建响应。

具体创建一个 WSGI 应用请查看文档,后面会陆续提到Flask框架中使用到Werkzeug的数据结构。这里贴一些官方文档的例子,使用werkzeug创建一个web 应用:

importos
importredis
importurlparse
fromwerkzeug.wrappersimportRequest,Response
fromwerkzeug.routingimportMap,Rule
fromwerkzeug.exceptionsimportHTTPException,NotFound
fromwerkzeug.wsgiimportSharedDataMiddleware
fromwerkzeug.utilsimportredirect
fromjinja2importEnvironment,FileSystemLoader
classShortly(object):
"""
Shortly是一个实际的WSGI应用,通过__call__方法直接调用wsgi_app,
同时通过一个可选设置创建一个中间件,将static文件夹暴露给用户:
"""
def__init__(self,config):
self.redis=redis.Redis(config['redis_host'],config['redis_port'])
defdispatch_request(self,request):
returnResponse('HelloWorld!')
defwsgi_app(self,environ,start_response):
request=Request(environ)
response=self.dispatch_request(request)
returnresponse(environ,start_response)
def__call__(self,environ,start_response):
returnself.wsgi_app(environ,start_response)
defcreate_app(redis_host='localhost',redis_port=6379,with_static=True):
app=Shortly({
'redis_host':redis_host,
'redis_port':redis_port
})
ifwith_static:
app.wsgi_app=SharedDataMiddleware(app.wsgi_app,{
'/static':os.path.join(os.path.dirname(__file__),'static')
})
returnapp

if__name__=='__main__':
fromwerkzeug.servingimportrun_simple
app=create_app()
run_simple('127.0.0.1',5000,app,use_debugger=True,use_reloader=True)

思路很简单,我们的 Shortly 是一个实际的 WSGI 应用。 __call__ 方法直接调用 wsgi_app 。这样做我们可以装饰 wsgi_app 调用中间件,就像我们在 create_app 函数中做的一样。

wsgi_app 实际上创建了一个 Request 对象,之后通过 dispatch_request 调用 Request 对象然后给 WSGI 应用返回一个 Response 对象。正如你看到的:无论是创建 Shortly 类,还是创建 Werkzeug Request 对象来执行 WSGI 接口。最终结果只是从 dispatch_request 方法返回另一个 WSGI 应用。这部分解释来源于官方文档的中文版。

总结


本文主要解释了WSGI规范和Werkzeug(WSGI 工具集),以及如何实现一个符合WSGI规范的WSGI应用,最后使用Werkzeug 工具集中的相关模块,快速实现了一个基于WSGI的简单应用。

参考


Werkzeug 中文文档
Werkzeug 英文文档
WSGI Servers
WSGI协议的原理和实现

原文来自:https://www.py.cn
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容