设为首页 收藏本站
查看: 1336|回复: 0

[经验分享] openstack nova 基础知识——wsgi

[复制链接]

尚未签到

发表于 2018-6-1 12:15:25 | 显示全部楼层 |阅读模式
激励自己的话:
在微博上看到一句话:一件事成功的概率只有1%,但是要是做上100遍的话,成功的概率将会是63%,这句话对现在的我真是一个极大的鼓励。


正文:
在nova源码中看到了wsgi这个模块,不懂,于是谷歌去,又全是英文啊!
官方网站:http://wsgi.readthedocs.org/en/latest/index.html


1.  什么是wsgi?

Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是Python应用程序或框架和Web服务器之间的一种接口,已经被广泛接受, 它已基本达成它了可移植性方面的目标。WSGI 没有官方的实现, 因为WSGI更像一个协议. 只要遵照这些协议,WSGI应用(Application)都可以在任何实现(Server)上运行, 反之亦然。


2.  如何实现WSGI?

看了几个例子,发现有这么几个“角色”:application、server、client,它们之间的关系是client发送请求给server,server转发这个请求给application,然后application进行一系列操作之后,将响应发送给server,server再将响应转发给client,server就起一个转发的作用。
WSGI就在application和server之间发挥作用:
首先是在server中定义了一个start_response(status,  response_headers,  exc_info=None)方法,返回值是一个write()函数,也就是在必须在执行过start_response()函数之后,才能执行write()方法。还定义了environ变量,即环境变量,里面存放的是server接收到的client端的环境变量。WSGI就是规定了server要将start_response和environ发送给application。
然后就是application就要有接收这两个参数的“接口”了,这个“接口”可以以各种方式实现:方法、函数、类都可以。接受到之后,就要在application端调用start_resopnse()方法,而且这个调用一定要在return之前。WSGI就是规定了application要实现接收这两个参数的“接口”,并且执行start_response()。
server在接收到application的响应之后,就开始write()数据给client,首先要判断start_response()方法执行了没有,如果没有执行,那么就报出:AssertionError("write() before start_response()") 这样的异常。如果执行了start_response(),那么write()就顺利执行。


经过这样的“接口”设计,就可以让application在任何server上运行了?Maybe吧!



3.  如何使用wsgi?
这里具一个简单的例子,是从官网上看到的,觉得很简单,很具有代表性:


  查看文本打印

  •   #! /usr/bin/env python  
  •     
  •   # Our tutorial's WSGI server  
  •   from wsgiref.simple_server import make_server  
  •     
  •   def application(environ, start_response):  
  •      “”“这个就是application,实现了接收这两个参数的接口,并且在下面调用了start_response()”“”  
  •      # Sorting and stringifying the environment key, value pairs  
  •      response_body = ['%s: %s' % (key, value)  
  •                       for key, value in sorted(environ.items())]  
  •      response_body = '\n'.join(response_body)  
  •     
  •      status = '200 OK'  
  •      response_headers = [('Content-Type', 'text/plain'),  
  •                     ('Content-Length', str(len(response_body)))]  
  •      start_response(status, response_headers)  
  •     
  •      return [response_body]  
  •     
  •   # Instantiate the WSGI server.  
  •   # It will receive the request, pass it to the application  
  •   # and send the application's response to the client  
  •   # 这个是server,在它内部定义了start_response()方法和environ变量,并且调用application  
  •   httpd = make_server(  
  •      'localhost', # The host name.  
  •      8051, # A port number where to wait for the request.  
  •      application # Our application object name, in this case a function.  
  •      )  
  •     
  •   # Wait for a single request, serve it and quit.  
  •   httpd.handle_request()  
  查看文本打印

  •   #! /usr/bin/env python  
  •     
  •   # Our tutorial's WSGI server  
  •   from wsgiref.simple_server import make_server  
  •     
  •   def application(environ, start_response):  
  •      “”“这个就是application,实现了接收这两个参数的接口,并且在下面调用了start_response()”“”  
  •      # Sorting and stringifying the environment key, value pairs  
  •      response_body = ['%s: %s' % (key, value)  
  •                       for key, value in sorted(environ.items())]  
  •      response_body = '\n'.join(response_body)  
  •     
  •      status = '200 OK'  
  •      response_headers = [('Content-Type', 'text/plain'),  
  •                     ('Content-Length', str(len(response_body)))]  
  •      start_response(status, response_headers)  
  •     
  •      return [response_body]  
  •     
  •   # Instantiate the WSGI server.  
  •   # It will receive the request, pass it to the application  
  •   # and send the application's response to the client  
  •   # 这个是server,在它内部定义了start_response()方法和environ变量,并且调用application  
  •   httpd = make_server(  
  •      'localhost', # The host name.  
  •      8051, # A port number where to wait for the request.  
  •      application # Our application object name, in this case a function.  
  •      )  
  •     
  •   # Wait for a single request, serve it and quit.  
  •   httpd.handle_request()  


如果想看server内部是如何实现的话,可以看一下PEP333上的这个例子:


  查看文本打印

  •   import os, sys  
  •     
  •   def run_with_cgi(application):  
  •     
  •       environ = dict(os.environ.items())  
  •       environ['wsgi.input']        = sys.stdin  
  •       environ['wsgi.errors']       = sys.stderr  
  •       environ['wsgi.version']      = (1, 0)  
  •       environ['wsgi.multithread']  = False  
  •       environ['wsgi.multiprocess'] = True  
  •       environ['wsgi.run_once']     = True  
  •     
  •       if environ.get('HTTPS', 'off') in ('on', '1'):  
  •           environ['wsgi.url_scheme'] = 'https'  
  •       else:  
  •           environ['wsgi.url_scheme'] = 'http'  
  •     
  •       headers_set = []  
  •       headers_sent = []  
  •     
  •       def write(data):  
  •           if not headers_set:  
  •                raise AssertionError("write() before start_response()")  
  •     
  •           elif not headers_sent:  
  •                # Before the first output, send the stored headers  
  •                status, response_headers = headers_sent[:] = headers_set  
  •                sys.stdout.write('Status: %s\r\n' % status)  
  •                for header in response_headers:  
  •                    sys.stdout.write('%s: %s\r\n' % header)  
  •                sys.stdout.write('\r\n')  
  •     
  •           sys.stdout.write(data)  
  •           sys.stdout.flush()  
  •     
  •       def start_response(status, response_headers, exc_info=None):  
  •           if exc_info:  
  •               try:  
  •                   if headers_sent:  
  •                       # Re-raise original exception if headers sent  
  •                       raise exc_info[0], exc_info[1], exc_info[2]  
  •               finally:  
  •                   exc_info = None     # avoid dangling circular ref  
  •           elif headers_set:  
  •               raise AssertionError("Headers already set!")  
  •     
  •           headers_set[:] = [status, response_headers]  
  •           return write  
  •     
  •       result = application(environ, start_response)  
  •       try:  
  •           for data in result:  
  •               if data:    # don't send headers until body appears  
  •                   write(data)  
  •           if not headers_sent:  
  •               write('')   # send headers now if body was empty  
  •       finally:  
  •           if hasattr(result, 'close'):  
  •               result.close()  
  查看文本打印

  •   import os, sys  
  •     
  •   def run_with_cgi(application):  
  •     
  •       environ = dict(os.environ.items())  
  •       environ['wsgi.input']        = sys.stdin  
  •       environ['wsgi.errors']       = sys.stderr  
  •       environ['wsgi.version']      = (1, 0)  
  •       environ['wsgi.multithread']  = False  
  •       environ['wsgi.multiprocess'] = True  
  •       environ['wsgi.run_once']     = True  
  •     
  •       if environ.get('HTTPS', 'off') in ('on', '1'):  
  •           environ['wsgi.url_scheme'] = 'https'  
  •       else:  
  •           environ['wsgi.url_scheme'] = 'http'  
  •     
  •       headers_set = []  
  •       headers_sent = []  
  •     
  •       def write(data):  
  •           if not headers_set:  
  •                raise AssertionError("write() before start_response()")  
  •     
  •           elif not headers_sent:  
  •                # Before the first output, send the stored headers  
  •                status, response_headers = headers_sent[:] = headers_set  
  •                sys.stdout.write('Status: %s\r\n' % status)  
  •                for header in response_headers:  
  •                    sys.stdout.write('%s: %s\r\n' % header)  
  •                sys.stdout.write('\r\n')  
  •     
  •           sys.stdout.write(data)  
  •           sys.stdout.flush()  
  •     
  •       def start_response(status, response_headers, exc_info=None):  
  •           if exc_info:  
  •               try:  
  •                   if headers_sent:  
  •                       # Re-raise original exception if headers sent  
  •                       raise exc_info[0], exc_info[1], exc_info[2]  
  •               finally:  
  •                   exc_info = None     # avoid dangling circular ref  
  •           elif headers_set:  
  •               raise AssertionError("Headers already set!")  
  •     
  •           headers_set[:] = [status, response_headers]  
  •           return write  
  •     
  •       result = application(environ, start_response)  
  •       try:  
  •           for data in result:  
  •               if data:    # don't send headers until body appears  
  •                   write(data)  
  •           if not headers_sent:  
  •               write('')   # send headers now if body was empty  
  •       finally:  
  •           if hasattr(result, 'close'):  
  •               result.close()  
  
4.  eventlet中的wsgi


因为nova中用的是eventlet中的wsgi,所以再来看一下wsgi在eventlet中是怎么实现的。其实不用看源码也可以知道evenlet中,将和服务器建立的连接放在了绿色线程中,socket用的也是绿化过的socket。简单的使用,如下示例:


  查看文本打印

  •   from eventlet import wsgi  
  •   import eventlet  
  •     
  •   def hello_world(env, start_response):  
  •       start_response('200 OK', [('Content-Type', 'text/plain')])  
  •       return ['Hello, World!\r\n']  
  •     
  •   wsgi.server(eventlet.listen(('', 8090)), hello_world)  
  查看文本打印

  •   from eventlet import wsgi  
  •   import eventlet  
  •     
  •   def hello_world(env, start_response):  
  •       start_response('200 OK', [('Content-Type', 'text/plain')])  
  •       return ['Hello, World!\r\n']  
  •     
  •   wsgi.server(eventlet.listen(('', 8090)), hello_world)  
  



参考资料:
http://webpython.codepoint.net/wsgi_tutorial
http://www.python.org/dev/peps/pep-0333/
http://eventlet.net/doc/modules/wsgi.html
  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-499847-1-1.html 上篇帖子: openstack_kilo+centos7创建Centos6.6镜像 下篇帖子: openstack cinder
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表