Skip to main content

moregeek program

openstack nova 基础知识——wsgi-多极客编程

激励自己的话:

在微博上看到一句话:一件事成功的概率只有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?

这里具一个简单的例子,是从官网上看到的,觉得很简单,很具有代表性:


查看文本打印

  1. #! /usr/bin/env python  

  2.   

  3. # Our tutorial's WSGI server  

  4. from wsgiref.simple_server import make_server  

  5.   

  6. def application(environ, start_response):  

  7.    “”“这个就是application,实现了接收这两个参数的接口,并且在下面调用了start_response()”“”  

  8.    # Sorting and stringifying the environment key, value pairs  

  9.    response_body = ['%s: %s' % (key, value)  

  10.                     for key, value in sorted(environ.items())]  

  11.    response_body = '\n'.join(response_body)  

  12.   

  13.    status = '200 OK'  

  14.    response_headers = [('Content-Type''text/plain'),  

  15.                   ('Content-Length', str(len(response_body)))]  

  16.    start_response(status, response_headers)  

  17.   

  18.    return [response_body]  

  19.   

  20. # Instantiate the WSGI server.  

  21. # It will receive the request, pass it to the application  

  22. and send the application's response to the client  

  23. # 这个是server,在它内部定义了start_response()方法和environ变量,并且调用application  

  24. httpd = make_server(  

  25.    'localhost', # The host name.  

  26.    8051, # A port number where to wait for the request.  

  27.    application # Our application object name, in this case a function.  

  28.    )  

  29.   

  30. # Wait for a single request, serve it and quit.  

  31. httpd.handle_request()  

查看文本打印

  1. #! /usr/bin/env python  

  2.   

  3. # Our tutorial's WSGI server  

  4. from wsgiref.simple_server import make_server  

  5.   

  6. def application(environ, start_response):  

  7.    “”“这个就是application,实现了接收这两个参数的接口,并且在下面调用了start_response()”“”  

  8.    # Sorting and stringifying the environment key, value pairs  

  9.    response_body = ['%s: %s' % (key, value)  

  10.                     for key, value in sorted(environ.items())]  

  11.    response_body = '\n'.join(response_body)  

  12.   

  13.    status = '200 OK'  

  14.    response_headers = [('Content-Type''text/plain'),  

  15.                   ('Content-Length', str(len(response_body)))]  

  16.    start_response(status, response_headers)  

  17.   

  18.    return [response_body]  

  19.   

  20. # Instantiate the WSGI server.  

  21. # It will receive the request, pass it to the application  

  22. and send the application's response to the client  

  23. # 这个是server,在它内部定义了start_response()方法和environ变量,并且调用application  

  24. httpd = make_server(  

  25.    'localhost', # The host name.  

  26.    8051, # A port number where to wait for the request.  

  27.    application # Our application object name, in this case a function.  

  28.    )  

  29.   

  30. # Wait for a single request, serve it and quit.  

  31. httpd.handle_request()  


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


查看文本打印

  1. import os, sys  

  2.   

  3. def run_with_cgi(application):  

  4.   

  5.     environ = dict(os.environ.items())  

  6.     environ['wsgi.input']        = sys.stdin  

  7.     environ['wsgi.errors']       = sys.stderr  

  8.     environ['wsgi.version']      = (10)  

  9.     environ['wsgi.multithread']  = False  

  10.     environ['wsgi.multiprocess'] = True  

  11.     environ['wsgi.run_once']     = True  

  12.   

  13.     if environ.get('HTTPS''off'in ('on''1'):  

  14.         environ['wsgi.url_scheme'] = 'https'  

  15.     else:  

  16.         environ['wsgi.url_scheme'] = 'http'  

  17.   

  18.     headers_set = []  

  19.     headers_sent = []  

  20.   

  21.     def write(data):  

  22.         if not headers_set:  

  23.              raise AssertionError("write() before start_response()")  

  24.   

  25.         elif not headers_sent:  

  26.              # Before the first output, send the stored headers  

  27.              status, response_headers = headers_sent[:] = headers_set  

  28.              sys.stdout.write('Status: %s\r\n' % status)  

  29.              for header in response_headers:  

  30.                  sys.stdout.write('%s: %s\r\n' % header)  

  31.              sys.stdout.write('\r\n')  

  32.   

  33.         sys.stdout.write(data)  

  34.         sys.stdout.flush()  

  35.   

  36.     def start_response(status, response_headers, exc_info=None):  

  37.         if exc_info:  

  38.             try:  

  39.                 if headers_sent:  

  40.                     # Re-raise original exception if headers sent  

  41.                     raise exc_info[0], exc_info[1], exc_info[2]  

  42.             finally:  

  43.                 exc_info = None     # avoid dangling circular ref  

  44.         elif headers_set:  

  45.             raise AssertionError("Headers already set!")  

  46.   

  47.         headers_set[:] = [status, response_headers]  

  48.         return write  

  49.   

  50.     result = application(environ, start_response)  

  51.     try:  

  52.         for data in result:  

  53.             if data:    # don't send headers until body appears  

  54.                 write(data)  

  55.         if not headers_sent:  

  56.             write('')   # send headers now if body was empty  

  57.     finally:  

  58.         if hasattr(result, 'close'):  

  59.             result.close()  

查看文本打印

  1. import os, sys  

  2.   

  3. def run_with_cgi(application):  

  4.   

  5.     environ = dict(os.environ.items())  

  6.     environ['wsgi.input']        = sys.stdin  

  7.     environ['wsgi.errors']       = sys.stderr  

  8.     environ['wsgi.version']      = (10)  

  9.     environ['wsgi.multithread']  = False  

  10.     environ['wsgi.multiprocess'] = True  

  11.     environ['wsgi.run_once']     = True  

  12.   

  13.     if environ.get('HTTPS''off'in ('on''1'):  

  14.         environ['wsgi.url_scheme'] = 'https'  

  15.     else:  

  16.         environ['wsgi.url_scheme'] = 'http'  

  17.   

  18.     headers_set = []  

  19.     headers_sent = []  

  20.   

  21.     def write(data):  

  22.         if not headers_set:  

  23.              raise AssertionError("write() before start_response()")  

  24.   

  25.         elif not headers_sent:  

  26.              # Before the first output, send the stored headers  

  27.              status, response_headers = headers_sent[:] = headers_set  

  28.              sys.stdout.write('Status: %s\r\n' % status)  

  29.              for header in response_headers:  

  30.                  sys.stdout.write('%s: %s\r\n' % header)  

  31.              sys.stdout.write('\r\n')  

  32.   

  33.         sys.stdout.write(data)  

  34.         sys.stdout.flush()  

  35.   

  36.     def start_response(status, response_headers, exc_info=None):  

  37.         if exc_info:  

  38.             try:  

  39.                 if headers_sent:  

  40.                     # Re-raise original exception if headers sent  

  41.                     raise exc_info[0], exc_info[1], exc_info[2]  

  42.             finally:  

  43.                 exc_info = None     # avoid dangling circular ref  

  44.         elif headers_set:  

  45.             raise AssertionError("Headers already set!")  

  46.   

  47.         headers_set[:] = [status, response_headers]  

  48.         return write  

  49.   

  50.     result = application(environ, start_response)  

  51.     try:  

  52.         for data in result:  

  53.             if data:    # don't send headers until body appears  

  54.                 write(data)  

  55.         if not headers_sent:  

  56.             write('')   # send headers now if body was empty  

  57.     finally:  

  58.         if hasattr(result, 'close'):  

  59.             result.close()  


4.  eventlet中的wsgi


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


查看文本打印

  1. from eventlet import wsgi  

  2. import eventlet  

  3.   

  4. def hello_world(env, start_response):  

  5.     start_response('200 OK', [('Content-Type''text/plain')])  

  6.     return ['Hello, World!\r\n']  

  7.   

  8. wsgi.server(eventlet.listen((''8090)), hello_world)  

查看文本打印

  1. from eventlet import wsgi  

  2. import eventlet  

  3.   

  4. def hello_world(env, start_response):  

  5.     start_response('200 OK', [('Content-Type''text/plain')])  

  6.     return ['Hello, World!\r\n']  

  7.   

  8. 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


WSGI初探-多极客编程

wsgi初探 前言 本文不涉及WSGI的具体协议的介绍,也不会有协议完整的实现,甚至描述中还会掺杂着本人自己对于WSGI的见解。所有的WSGI官方定义请看http://www.python.org/dev/peps/pep-3333/。 WSGI是什么? WSGI的官方定义是,the Python Web Server Gateway Interface。从名字就可以看出来,这东西是一个Gatew

mac配置 Django 1.7.1 +mod_wsgi 4.4.7(非daemon) +Apache/2.2.26 (Unix)-多极客编程

今天准备想把django配置到apache 服务器上,那个糟心。。看了几个博客 要么就是草草一笔,要么就是不带版本号,搞得 晕头转向 最后我还是自己看官方文档弄明白了,这里写一个稍微详细一点的总结,适合不太懂的小白,因为我就是。。。。。- -!再次声明我现在的版本:Django 1.7.1 +mod_wsgi 4.4.7(非daemon) +Apache/2.2.26 mac 我没升级 Yosom

Django+ Mod_wsgi-多极客编程

安装环境   centos 6.4    apache 2.2    python 2.7    sqlite32.软件安装    1.安装apache          yum install -y httpd  httpd-devel    2.安装sqlite3               wget http://www.sqlite.org/sqlite-autoconf-3070500.

Linux + Apache + MySQL 环境下OSQA部署-多极客编程

官方的安装指南: http://wiki.osqa.net/display/docs安装环境:linuxmint11, python2.7, django1.3, apache2.2。本文中,linux的用户名为neil,在安装过程中一些路径请注意替换为真实路径。1.  下载OSQA1)  svn下载sudo apt-get install subversion #下载subversion svn

Django -- 整合apache、nginx-多极客编程

前面章节我们都是通过python manage.py runserver运行服务器,访问django,但这只适用于测试环境。当项目正式发布后,我们需要一个稳定可持续的服务器,比如apache、nginx等等。接下来我们将用apache、nginx启动服务器。wsgi:一种实现了python解析的通用接口标准/协议,实现了python web程序与服务器交互。uwsgi:他也是一种通信协议,是uWS

wsgi(django与apache整合)-多极客编程

wsgi   (web server gateway interface)官方文档:https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/modwsgi/1、安装wsgi[root@133 ~]# yum install mod_wsgi2、修该django.py配置文件[root@133 conf.d]# vim /etc/htt