一。前言

WSGI服务器

一个Web服务器网关接口 (WSGI)服务器实现了WSGI接口的Web服务器端运行的Python的Web应用程序。

为什么需要WSGI?

传统的Web服务器不理解或有任何方式来运行Python应用程序。在20世纪90年代后期,名为Grisha Trubetskoy的开发人员 提出了一个名为mod_python的Apache模块 来执行任意的Python代码。在20世纪90年代后期和21世纪初,Apache配置的mod_python运行了大多数Python Web应用程序。

但是,mod_python不是标准规范。这只是一个允许Python代码在服务器上运行的实现。由于mod_python的开发陷入僵局,安全漏洞被发现,社区认识到,需要一致的方式来执行Web应用程序的Python代码。

因此,Python社区提出了WSGI作为模块和容器可以实现的标准接口。WSGI现在是运行Python Web应用程序的被接受的方法。

WSGI官方规范

WSGI标准v1.0在PEP 0333中指定 。截至2010年9月,WSGI v1.0被PEP 3333取代 ,它定义了v1.0.1 WSGI标准。如果您使用Python 2.x,并且您符合PEP 0333,那么您也符合3333.较新版本仅仅是Python 3的更新,并且有关于如何处理unicode的说明。

在的wsgiref的Python 2.x中和 的wsgiref在Python 3.x的 是内置到Python的标准库WSGI规范的参考实现,因此它可以被用来建造WSGI服务器和应用程序

PEP 0333 – Python Web Server Gateway Interface 是一种 web server or gateway 和 python web application or framework 之间简单通用的接口,符合这种接口的 application 可运行在所有符合该接口的 server 上。通俗的讲,WSGI 规范了一种简单的接口,解耦了 server 和 application,使得双边的开发者更加专注自身特性的开发。

  • Web server/gateway: 即 HTTP Server,处理 HTTP 协议,接受用户 HTTP 请求和提供并发,调用 web application 处理业务逻辑。通常采用 C/C++ 编写,代表:apache, nginx 和 IIS。
  • Python Web application/framework: 专注业务逻辑的 python 应用或者框架

Python Web application/framework

Application/framework 端必须定义一个 callable object,callable object 可以是以下三者之一:

    • function, method
    • class
    • instance with a __call__ method

Callable object 必须满足以下两个条件:

    • 接受两个参数:字典(environ),回调函数(start_response,返回 HTTP status,headers 给 web server)
    • 返回一个可迭代的值

示例:

  1. def application(environ, start_response):
  2. start_response('200 OK', [('Content-Type', 'text/plain')])
  3. return ['HELLO WORLD!']
  1. class ApplicationClass(object):
  2. def __init__(self, environ, start_response):
  3. self.environ = environ
  4. self.start_response = start_response
  5.  
  6. def __iter__(self):
  7. self.start_response('200 OK', [('Content-type', 'text/plain')])
  8. yield "Hello world!n"
  1. environ 和 start_response 由 http server 提供并实现
  2. environ 变量是包含了环境信息的字典
  3. Application 内部在返回前调用 start_response
  4. start_response也是一个 callable,接受两个必须的参数,status(HTTP状态)和 response_headers(响应消息的头)
  5. 可调用对象要返回一个值,这个值是可迭代的

服务器接口端

服务器端主要专注 HTTP 层面的业务,重点是接收 HTTP 请求和提供并发。

每当收到 HTTP 请求,服务器接口端必须调用 callable object:

  • 接收 HTTP 请求,但是不关心 HTTP url, HTTP method 等
  • 为 environ 提供必要的参数,实现一个回调函数 start_response,并传给 callable object
  • 调用 callable object

Middleware,中间件

  Middleware 处于 服务层和 应用接口层 之间,每个 middleware 实现不同的功能,我们通常根据需求选择相应的 middleware 并组合起来,实现所需的功能。其作用有以下几点:

  • 根据 url 把用户请求调度到不同的 application 中。
  • 负载均衡,转发用户请求
  • 预处理 XSL 等相关数据
  • 限制请求速率,设置白名单
  1. class IPBlacklistMiddleware(object):
  2. def __init__(self, app):
  3. self.app = app
  4.  
  5. def __call__(self, environ, start_response):
  6. ip_addr = environ.get('HTTP_HOST').split(':')[0]
  7. if ip_addr not in ('127.0.0.1'):
  8. return forbidden(start_response)
  9.  
  10. return self.app(environ, start_response)
  11.  
  12. def forbidden(start_response):
  13. start_response('403 Forbidden', [('Content-Type', 'text/plain')])
  14. return ['Forbidden']
  15.  
  16. def application(environ, start_response):
  17. start_response('200 OK', [('Content-Type', 'text/plain')])
  18. return ['Hello World!']
  19.  
  20. if __name__ == '__main__':
  21. from wsgiref.simple_server import make_server
  22. application = IPBlacklistMiddleware(application)
  23. server = make_server('0.0.0.0', 8080, application)
  24. server.serve_forever()

 大致了解WSGI框架后我们来看下Paste+Pastedeploy+route+webob开发,openstack开发使用的就是此开发框架,主要使用到的一些模块是:

  • eventlet: python 的高并发网络库
  • paste.deploy: 用于发现和配置 WSGI application 和 server 的库
  • routes: 处理 http url mapping 的库
  • webob: 处理HTTP请求并提供了一个对象来方便的处理返回response消息

Eventlet

Eventlet 是一个基于协程的 Python 高并发网络库,额以下特点:

  • 使用 epoll、kqueue 或 libevent 等 I/O 复用机制,对于非阻塞 I/O 具有良好的性能
  • 基于协程(Coroutines),和进程、线程相比,其切换开销更小,具有更高的性能
  • 简单易用,特别是支持采用同步的方式编写异步的代码

paste.deploy

Paste Deployment是用于查找和配置WSGI应用程序和服务器的系统。对于WSGI应用程序消费者,它提供了从配置文件或Python Egg加载WSGI应用程序的单一简单函数(loadapp)。对于WSGI应用程序提供商,它只需要一个简单的入口点到您的应用程序,以便应用程序用户不需要暴露于应用程序的实现细节。

Paste.deploy 通常要求 application 实现一个 factory 的类方法,如下:

  1. class TestApplication(object):
  2. def __init__(self):
  3. pass
  4.  
  5. @webob.dec.wsgify
  6. def __call__(self, req):
  7. return self.router
  8.  
  9. @classmethod
  10. def factory(cls, global_conf, **local_conf):
  11. return cls()
  12.  
  13. if '__main__' == __name__:
  14. application = loadapp('config:%s/config.ini' % (CONF))
  15. server = eventlet.spawn(wsgi.server,
  16. eventlet.listen(('0.0.0.0', 8080)), application)
  17. server.wait()

Paste.deploy 的.ini配置文件配置 讲解

配置文件说明,一个配置文件有不同的分段,但pastedeploy 关心的是前缀,比如app:main or filter:errors,:分隔部分之后是是这个分段的name,前一部分是这个分段的type类型,前段给的类型,后段名字将被忽略。

一个简单的INI配置文件格式是 name = value.可以通过缩进后续行来扩展配置,#是对前面配置的评论标注。

通常,您有一个或两个部分,称为“main”:一个应用程序部分(app:main)和一个服务器部分(server:main)。(复合:…表示向多个应用程序发送的内容(如以下示例)。

  1. [composite:main]
  2. use = egg:Paste#urlmap
  3. / = home
  4. /blog = blog
  5. /wiki = wiki
  6. /cms = config:cms.ini
  7.  
  8. [app:home]
  9. use = egg:Paste#static
  10. document_root = %(here)s/htdocs
  11.  
  12. [filter-app:blog]
  13. use = egg:Authentication#auth
  14. next = blogapp
  15. roles = admin
  16. htpasswd = /home/me/users.htpasswd
  17.  
  18. [app:blogapp]
  19. use = egg:BlogApp
  20. database = sqlite:/home/me/blog.db
  21.  
  22. [app:wiki]
  23. use = call:mywiki.main:application
  24. database = sqlite:/home/me/wiki.db

urlmap 相当于做了多路由的分发,请求http://xxxx/ 时会请求分段名称为home的app, 走到相对的处理函数或者controller,其他类同

第一分段解释:

  1. [composite:main]
  2. use = egg:Paste#urlmap
  3. / = home
  4. /blog = blog
  5. /cms = config:cms.ini

composite 分段将请求分发给其他applications程序,use = egg:Paste#urlmap 意思是这个composite程序将使用paste名称为urlmap的包, urlmap是一个特别常见的复合应用程序,它使用路径前缀将请求映射到另一个应用程序。其他的如/ /blog 是应用程序,最后一个/cms,表明指的是另一个ini配置文件。

  1. [app:home]
  2. use = egg:Paste#static
  3. document_root = %(here)s/htdocs

egg:Paste#static 静态文件配置,使用paste包static只提供静态文件,需要指定document_root目录

使用方法

  1. from paste.deploy import loadapp
  2. wsgi_app = loadapp('config:/path/to/config.ini')

section的type可以有:app、composite、filter、pipeline、filter-app等。学习具体更多配置详参官网

Route

Routes 是基于 ruby on rails 的 routes system 开发的 python 库,它根据 http url 把请求映射到具体的方法,routes 简单易用,可方便的构建 Restful 风格的 url。

示例:

  1. import eventlet
  2. from eventlet import wsgi
  3. from paste.deploy import loadapp
  4. import routes
  5. import routes.middleware as middleware
  6. import webob.dec
  7. import webob.exc
  8.  
  9. from manager.settings import CONF
  10.  
  11. class TestController(object):
  12.  
  13. def index(self, req):
  14. return 'GET'
  15.  
  16. def create(self, req):
  17. return 'POST'
  18.  
  19. def delete(self, req):
  20. return 'DELETE'
  21.  
  22. def update(self, req):
  23. return 'PUT'
  24.  
  25. class Resource(object):
  26. def __init__(self, controller):
  27. self.controller = controller()
  28.  
  29. @webob.dec.wsgify
  30. def __call__(self, req):
  31. match = req.environ['wsgiorg.routing_args'][1]
  32. action = match['action']
  33. if hasattr(self.controller, action):
  34. method = getattr(self.controller, action)
  35. return method(req)
  36. return webob.exc.HTTPNotFound()
  37.  
  38. class TestApplication(object):
  39. def __init__(self):
  40. self.mapper = routes.Mapper()
  41. self.mapper.resource('test', 'tests', controller=Resource(TestController))
  42. self.router = middleware.RoutesMiddleware(self.dispatch, self.mapper)
  43.  
  44. @webob.dec.wsgify
  45. def __call__(self, req):
  46. return self.router
  47.  
  48. @classmethod
  49. def factory(cls, global_conf, **local_conf):
  50. return cls()
  51.  
  52. @staticmethod
  53. @webob.dec.wsgify
  54. def dispatch(req):
  55. match = req.environ['wsgiorg.routing_args'][1]
  56. return match['controller'] if match else webob.exc.HTTPNotFound()
  57.  
  58. if '__main__' == __name__:
  59. application = loadapp('config:%s/config.ini' % (CONF))
  60. server = eventlet.spawn(wsgi.server,
  61. eventlet.listen(('0.0.0.0', 8080)), application)
  62. server.wait()

WSGI框架及Paste+Pastedeploy+route+webob开发的更多相关文章

  1. Openstack Restful API 开发框架 Paste + PasteDeploy + Routes + WebOb

    目录 目录 Paste PasteDeploy Routes WebOb 简介 WSGI入口 Paste和PasteDeploy 配置文件 pasteini 中间件的实现 Routes WebOb 参 ...

  2. 使用MVVM框架(avalonJS)进行快速开发

    背景 在运营活动开发中,因为工作的重复性很大,同时往往开发时间短,某些情况下也会非常紧急,导致了活动开发时间被大大压缩,同时有些活动逻辑复杂,数据或者状态变更都需要手动渲染,容易出错,正是因为这些问题 ...

  3. Scala 的 Web 框架 Lift 开始 3.0 版本开发

    Scala 的 Web 框架 Lift 开始 3.0 版本开发 http://demo.liftweb.net/ http://liftweb.net/download Lift 框架在不断的成长和改 ...

  4. django框架实现restful风格的API开发

    RESTful风格的要求:https://www.cnblogs.com/chichung/p/9933116.html 利用django原生的框架直接做RESTful的API开发是怎样的呢?感受一下 ...

  5. python-django框架-电商项目-订单模块开发_20191125

    python-django框架-电商项目-订单模块开发 提交订单页面: 在购物车中点击提交订单,就应该到达提交订单页面了, 显示: 1,收获地址, 2,支付方式 3,用户购买的商品信息,数量,小计, ...

  6. python-django框架-电商项目-购物车模块开发_20191125

    python-django框架-电商项目-购物车模块开发 商品详情页js代码: 在商品详情页,有加入购物车按钮, 点击加减号可以增加减少,手动输入也可以, 点击加入购物车,就要加过去, 先实现加减的操 ...

  7. nodejs 中koa框架下的微信公众号开发初始篇

    最近在搞微信公众号开发,后端采用的是nodejs下的koa框架,初识后端的菜鸟,自己搞难度太大了,网上找了很多文章,采用的中间件大都是express框架下的,不过好在爬了许多坑之后总算看见点曙光了,遂 ...

  8. (转)python WSGI框架详解

    原文:https://www.cnblogs.com/shijingjing07/p/6407723.html?utm_source=itdadao&utm_medium=referral h ...

  9. WSGI学习系列Paste

    Paste has been under development for a while, and has lots of code in it. The code is largely decoup ...

随机推荐

  1. Mybatis第五篇【Mybatis与Spring整合】

    Mybatis与Spring整合 既然我们已经学了Mybatis的基本开发了,接下来就是Mybatis与Spring的整合了! 以下使用的是Oracle数据库来进行测试 导入jar包 aopallia ...

  2. 关于极光推送Jpush的demo

    关于极光推送Jpush 推送是手机app必不可少的一样功能,这次由于公司项目需要研究了一下.由于推送一般写于服务端,所以对于不会Android的javaweb程序员要写出一个完整的demo是一件很头痛 ...

  3. MongoDB 复制篇

    mongoDB 复制篇 复制集简介 Mongodb复制集由一组Mongod实例(进程)组成,包含一个Primary节点和多个Secondary节点,Mongodb Driver(客户端)的所有数据都写 ...

  4. 过度拟合(overfilting)

    过拟合概念:是指分类器能够百分之百的正确分类样本数据(训练集中的样本数据),对训练集以外的数据却不能够正确分类. 原因:1:模型(算法)太过复杂,比如神经网络,算法太过精细复杂,规则太过严格,以至于任 ...

  5. ACM-ICPC北京赛区(2017)网络赛_Minimum

    题目9 : Minimum 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 You are given a list of integers a0, a1, -, a2^k ...

  6. Linux JDK配置

    第一步:下载jdk-7-linux-i586.tar.gz wget -c http://download.oracle.com/otn-pub/java/jdk/7/jdk-7-linux-i586 ...

  7. CentOS 7搭建LAMP环境(一)

    CentOS是Linux发行版之一,它是来自于Red Hat Enterprise Linux依照开放源代码规定释出的源代码所编译而成.由于出自同样的源代码,因此有些要求高度稳定性的服务器以CentO ...

  8. [bzoj1066] [SCOI2007] 蜥蜴 - 网络流

    在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个 ...

  9. js-注释代码习惯

    功能块代码 /** * xxxx */ 定义的函数或方法 /* xxxx */ 调用了某个函数或方法 // <--xxx

  10. 【转】python数据格式化之pprint

    pprint – 美观打印 作用:美观打印数据结构 pprint 包含一个“美观打印机”,用于生成数据结构的一个美观视图.格式化工具会生成数据结构的一些表示,不仅可以由解释器正确地解析,而且便于人类阅 ...