关闭

openstack 中的WSGI

961人阅读 评论(0) 收藏 举报
分类:

WSGI 程序起步

本文中程序的放置路径及运行方式在 Window + Apache + WSGI 配置指明。


第一WSGI程序

  1. def spch_wsgi(environ, start_response):  
  2.     
  3.     status = '200 OK'  
  4.     response_headers = [('Content-Type''text/plain')]  
  5.     start_response(status, response_headers)  
  6.   
  7.     return ['Hello World!']  
  8.   
  9. application = spch_wsgi  

WSGI server检索application函数, 并传递两个参数environ, start_response。

environ 为一个字典,包含环境变量。

start_response 为一个函数, 用于返回状态信息。


一个WSGI程序要完成两件事:

     其一:返回HTTP header。本例中, 状态‘200 OK‘, 表明一切正常。

     其二:返回一个iterable containing, 本例中是一个list。



输出environ信息

  1. def application(environ, start_response):  
  2.   
  3.     response_body = ""  
  4.     for k in environ:  
  5.         tmp = "%s = %s \n" % (k, environ[k])  
  6.         response_body += tmp  
  7.       
  8.     status = '200 OK'  
  9.     response_headers = [('Content-Type''text/plain')]  
  10.     start_response(status, response_headers)  
  11.       
  12.     return [response_body]  

  1. wsgi.multiprocess = False   
  2. SERVER_PROTOCOL = HTTP/1.1   
  3. SERVER_SOFTWARE = Apache/2.2.22 (Win32) mod_wsgi/3.3 Python/2.7.4   
  4. SCRIPT_NAME = /wsgi   
  5. mod_wsgi.handler_script =    
  6. SERVER_SIGNATURE =    
  7. REQUEST_METHOD = GET   
  8. PATH_INFO =    
  9. PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC   
  10. QUERY_STRING =    
  11. HTTP_USER_AGENT = Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0   
  12. HTTP_CONNECTION = keep-alive   
  13. SERVER_NAME = localhost   
  14. REMOTE_ADDR = 127.0.0.1   
  15. mod_wsgi.request_handler = wsgi-script   
  16. wsgi.url_scheme = http   
  17. mod_wsgi.callable_object = application   
  18. SERVER_PORT = 80   
  19. mod_wsgi.version = (3, 3)   
  20. mod_wsgi.input_chunked = 0   
  21. SERVER_ADDR = 127.0.0.1   
  22. DOCUMENT_ROOT = D:/Program Files (x86)/Apache Software Foundation/Apache2.2/htdocs   
  23. mod_wsgi.process_group =    
  24. COMSPEC = C:\Windows\system32\cmd.exe   
  25. SCRIPT_FILENAME = C:/wsgi_app/wsgi_handler.py   
  26. SERVER_ADMIN = admin@localhost.com   
  27. wsgi.input = <mod_wsgi.Input object at 0x01379DE0>   
  28. HTTP_HOST = localhost   
  29. wsgi.multithread = True   
  30. SystemRoot = C:\Windows   
  31. REQUEST_URI = /wsgi   
  32. HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8   
  33. WINDIR = C:\Windows   
  34. wsgi.version = (1, 1)   
  35. GATEWAY_INTERFACE = CGI/1.1   
  36. wsgi.run_once = False   
  37. wsgi.errors = <mod_wsgi.Log object at 0x01379D40>   
  38. REMOTE_PORT = 64214   
  39. HTTP_ACCEPT_LANGUAGE = zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3   
  40. mod_wsgi.application_group = 192.168.209.1|/wsgi   
  41. mod_wsgi.script_reloading = 1   
  42. wsgi.file_wrapper = <built-in method file_wrapper of mod_wsgi.Adapter object at 0x012E1770>   
  43. HTTP_ACCEPT_ENCODING = gzip, deflate   


上述代码也可以通过类来实现,类中要重载__call__,这样的好处是可以从其它类继承,复用代码。

  1. class MyApp:  
  2.     def __call__(self, environ, start_response):  
  3.         response_body = ['Hello World!']  
  4.    
  5.         status = '200 OK'  
  6.         response_headers = [('Content-Type''text/plain')]  
  7.         start_response(status, response_headers)  
  8.   
  9.         return response_body  
  10.           
  11. application = MyApp()  

假定存在一个superSession模块,用于追踪用户访问行为。

  1. import superSession  
  2. session = superSession.session()  
  3. print "Content-type: text/plain\n\n"  
  4.   
  5. if session.has_key('visited'):  
  6.     print "You have already visited!"  
  7. else:  
  8.     session['visited'] = 1  
  9.     print "This is your first visit."  

上述代码创建了一个Session对象,追踪用户访问行为。将上述思想用于WSGI程序中。


  1. def application(environ, start_response):  
  2.     import superSession  
  3.     session = superSession.session()  
  4.     if session.has_key('visited'):  
  5.         text = "You have already visited!"  
  6.     else:  
  7.         session['visited'] = 1  
  8.         text = "This is your first visit."  
  9.     start_response('200 OK', [('Content-type','text/plain')])  
  10.     return [text]  

可以将上述代码进行重构。


  1. def exampleApplication(environ, start_response):  
  2.     if environ['superSession'].has_key('visited'):  
  3.         text = "You have already visited!"  
  4.     else:  
  5.         environ['superSession']['visited'] = 1  
  6.         text = "This is your first visit."  
  7.     start_response('200 OK', [('Content-type','text/plain')])  
  8.     return [text]  
  9.       
  10. def session(application):  
  11.     def app(environ, start_response):  
  12.         if "superSession" not in environ:  
  13.             import superSession  
  14.             environ["superSession"] = superSession.session()  
  15.         return application(environ, start_response)  
  16.     return app  
  17.       
  18. application = session(exampleApplication)  

将session代码抽离放于session函数中,该函数专门用于判断用户访问行为。session函数将判断结果至于环境变量environ字典中。
exampleApplication通过environ字典获得用户访问行为。

我们称session函数为middleware,它处于server与application之间,对server传来的请求做相应的处理;它对于Server和application是透明的。
middleware的好处在于,通过middleware(本例中session函数)可以很简单的给WSGI程序添加新功能。


我们也可见将middleware包装成类,这样,我们可以通过继承,复用现有的中间件。类中要重载__call__。

  1. class Session:  
  2.     def __init__(self, application):  
  3.         self.application = application  
  4.   
  5.     def __call__(self, environ, start_response):  
  6.         if "superSession" not in environ:  
  7.             import superSession  
  8.             environ["superSession"] = superSession.session() # Options would obviously need specifying  
  9.         return self.application(environ,start_response)  
  10.           
  11. application = Session(exampleApplication)  


附录: 代码语法解释

  1. def session(application):  
  2.     def app(environ, start_response):  
  3.         if "superSession" not in environ:  
  4.             import superSession  
  5.             environ["superSession"] = superSession.session()  
  6.         return application(environ, start_response)  
  7.     return app  
  8.       
  9. application = session(exampleApplication)  

将exampleApplication传入session函数,session函数中定义了一个新的函数app,session将app返回赋给application。

实际上相当于application = app。app函数中进行相应处理(superSession),将处理好的environ在传递给exampleApplication。


3 webob request response

Request

Webob的Request对象,提供对WSGI environ环境变量的包装,通过webob可以很容易的读写environ字典。

environ字典内容如下:

  1. TMP = C:\Users\spch2008\AppData\Local\Temp   
  2. PYTHONIOENCODING = GBK   
  3. COMPUTERNAME = SPCH2008   
  4. wsgi.multiprocess = False   
  5. PROCESSOR_LEVEL = 16   
  6. USERDOMAIN = SPCH2008   
  7. VS100COMNTOOLS = D:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\Tools\   
  8. HTTP_ACCEPT_LANGUAGE = zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3   
  9. SERVER_PROTOCOL = HTTP/1.1   
  10. SERVER_SOFTWARE = WSGIServer/0.1 Python/2.7.4   
  11. PSMODULEPATH = C:\Windows\system32\WindowsPowerShell\v1.0\Modules\   
  12. SCRIPT_NAME =    
  13. COMMONPROGRAMFILES = C:\Program Files (x86)\Common Files   
  14. PROCESSOR_IDENTIFIER = AMD64 Family 16 Model 5 Stepping 3, AuthenticAMD   
  15. REQUEST_METHOD = GET   
  16. PROGRAMFILES = C:\Program Files (x86)   
  17. PROCESSOR_REVISION = 0503   
  18. PATH = D:/Program Files (x86)/java/jre7/bin/client;D:/Program Files (x86)/java/jre7/bin;D:/Program Files (x86)/java/jre7/lib/i386;C:\python32\;C:\python32\Lib\site-packages\;C:\python32\Scripts\;C:\Program Files (x86)\Common Files\NetSarang;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;D:\Program Files (x86)\java\jre7\bin;D:\Program Files (x86)\Rational\common;D:\Program Files (x86)\eclipse;   
  19. QUERY_STRING =    
  20. SYSTEMROOT = C:\Windows   
  21. PROGRAMFILES(X86) = C:\Program Files (x86)   
  22. PT5HOME = d:\Program Files (x86)\Cisco Packet Tracer 5.3.3   
  23. CONTENT_LENGTH =    
  24. HTTP_USER_AGENT = Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0   
  25. HTTP_CONNECTION = keep-alive   
  26. TEMP = C:\Users\spch2008\AppData\Local\Temp   
  27. REMOTE_ADDR = 127.0.0.1   
  28. COMMONPROGRAMFILES(X86) = C:\Program Files (x86)\Common Files   
  29. PROCESSOR_ARCHITECTURE = x86   
  30. wsgi.url_scheme = http   
  31. ALLUSERSPROFILE = C:\ProgramData   
  32. PYDEV_CONSOLE_ENCODING = GBK   
  33. SERVER_PORT = 8080   
  34. LOCALAPPDATA = C:\Users\spch2008\AppData\Local   
  35. HOMEPATH = \Users\spch2008   
  36. USERDOMAIN_ROAMINGPROFILE = SPCH2008   
  37. PROGRAMW6432 = C:\Program Files   
  38. USERNAME = spch2008   
  39. HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8   
  40. LOGONSERVER = \\MicrosoftAccount   
  41. PROMPT = $P$G   
  42. COMSPEC = C:\Windows\system32\cmd.exe   
  43. PROGRAMDATA = C:\ProgramData   
  44. PYTHONPATH = D:\Program Files (x86)\eclipse\plugins\org.python.pydev_2.7.3.2013031601\pysrc\pydev_sitecustomize;E:\GitHub\OpenStack\WSGI;C:\python32\DLLs;C:\python32\lib;C:\python32\lib\plat-win;C:\python32\lib\lib-tk;C:\python32;C:\python32\lib\site-packages   
  45. PATH_INFO = /   
  46. wsgi.multithread = True   
  47. wsgi.input = <socket._fileobject object at 0x0285C030>   
  48. wsgi.errors = <open file '<stderr>', mode 'w' at 0x01DA60D0>   
  49. HTTP_HOST = localhost:8080   
  50. SESSIONNAME = Console   
  51. PATHEXT = .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC   
  52. ASL.LOG = Destination=file   
  53. FP_NO_HOST_CHECK = NO   
  54. WINDIR = C:\Windows   
  55. wsgi.file_wrapper = wsgiref.util.FileWrapper   
  56. HTTP_ACCEPT_ENCODING = gzip, deflate   
  57. wsgi.version = (1, 0)   
  58. APPDATA = C:\Users\spch2008\AppData\Roaming   
  59. HOMEDRIVE = C:   
  60. SERVER_NAME = spch2008   
  61. wsgi.run_once = False   
  62. REMOTE_HOST = spch2008   
  63. SYSTEMDRIVE = C:   
  64. GATEWAY_INTERFACE = CGI/1.1   
  65. PYDEV_COMPLETER_PYTHONPATH = D:\Program Files (x86)\eclipse\plugins\org.python.pydev_2.7.3.2013031601\pysrc   
  66. NUMBER_OF_PROCESSORS = 4   
  67. DJANGO_SETTINGS_MODULE = WSGI.settings   
  68. CONTENT_TYPE = text/plain   
  69. PROCESSOR_ARCHITEW6432 = AMD64   
  70. COMMONPROGRAMW6432 = C:\Program Files\Common Files   
  71. OS = Windows_NT   
  72. PUBLIC = C:\Users\Public   
  73. USERPROFILE = C:\Users\spch2008  

  1. req = Request(environ)  

通过Request操作上述环境变量,所得结果如下:

req.method             'Get'
req.path_info            '/'
req.content_type     'text/plain'
req.remote_user     'None'
req.host                    'localhost:8080'

即通过req,可以很方便的读取environ环境变量,更多操作请看:http://docs.webob.org/en/latest/modules/webob.html


Response

Response包含了所有响应WSGI Server需要的变量。

  1. res = Response()  
  2. res.status = 200  
  3. res.headerlist = [('Content-type''text/html')]  
  4. res.body = 'Hello World!'  

使用webob改写之前的Hello World程序。j将上述代码粘贴到eclipse中,运行。

  1. from wsgiref.simple_server import make_server  
  2. from webob import Request, Response  
  3.   
  4. class MyApp:  
  5.     def __call__(self, environ, start_response):  
  6.           
  7.         req = Request(environ)  
  8.         res = Response()  
  9.          
  10.         res.status = 200  
  11.         res.headerlist = [('Content-Type''text/plain')]  
  12.         res.body = "Hello World!"  
  13.           
  14.         return res(environ, start_response)  
  15.           
  16. application = MyApp()  
  17.   
  18. httpd = make_server('localhost'8080, application)    
  19. httpd.serve_forever()   
Webob WSGI 装饰器

wsgify装饰器将一个普通函数转变成WSGI应用程序。

class webob.dec.wsgify(func=None, RequestClass=None, args=(), kwargs=None, middleware_wraps=None)


小示例

  1. from wsgiref.simple_server import make_server  
  2. from webob import Request, Response  
  3. from webob.dec import *  
  4.  
  5. @wsgify  
  6. def test(req):  
  7.     res = Response()  
  8.     res.status = 200  
  9.     res.body   = "spch"  
  10.     return res  
  11.   
  12. class MyApp:  
  13.     def __call__(self, environ, start_response):  
  14.           
  15.         req = Request(environ)  
  16.           
  17.         return test(environ, start_response)  
  18.           
  19. application = MyApp()  
  20.   
  21. httpd = make_server('localhost'8081, application)    
  22. httpd.serve_forever()   
其中,参数req为一个Request实例,可以通过req读取相应环境变量。

而且,我们可以定制装饰器

  1. from wsgiref.simple_server import make_server  
  2. from webob import Request, Response  
  3. from webob.dec import *  
  4. from webob.exc import *  
  5.   
  6. class MyRequest(Request):  
  7.     @property  
  8.     def is_local(self):  
  9.         return self.remote_addr == '127.0.0.1'  
  10.      
  11. @wsgify(RequestClass=MyRequest)  
  12. def myfunc(req):  
  13.     if req.is_local:  
  14.         return Response('hi!')  
  15.     else:  
  16.         raise HTTPForbidden  
  17.   
  18. class MyApp:  
  19.     def __call__(self, environ, start_response):  
  20.           
  21.         req = Request(environ)  
  22.           
  23.         return myfunc(environ, start_response)  
  24.           
  25. application = MyApp()  
  26.   
  27. httpd = make_server('localhost'8081, application)    
  28. httpd.serve_forever()   

如何是本机访问,则输出’hi‘,否则不允许
  1. from routes import Mapper  
  2. map = Mapper()  
  3. map.connect('spch''/blog', controller='main', action='index')  
  4.   
  5. result = map.match('/blog')  
  6. print result  
  7. {'action': u'index''controller': u'main'}  

1.2 行创建一个mapper
3.   行注册一条路由, 路由名称为'spch', 路径为'/blog', controller为main,
      action为index
      可以这样认为,匹配到此条路由的请求交由controller处理,请求预调用的
      函数为index

5. 创建好路由条目后,即可以进行匹配,调用match方法,匹配路径'blog'
6. 输出匹配结果

  1. map.connect(None"/error/{action}/{id}", controller="error")  
  2. result = map.match('/error/index/2')  
  3. print result  
  4. {'action': u'index''controller': u'error''id': u'2'}  

1.注册了一条无名路由,并且action从匹配路由中获得
  同样,我们可以省掉None
  map.connect("/error/{action}/{id}", controller="error")
  上述语句同样注册了一条无名路由。


Conditions

Conditions用于限制进行路由匹配,比如method

  1. m.connect("/user/list", controller="user", action="list", conditions=dict(method=["GET""HEAD"]))  
只匹配GET,HEAD请求。


Requirements

有时只想匹配数字,或者匹配可选的几个条目

  1. map.connect(R"/blog/{id:\d+}")  
  2. map.connect(R"/download/{platform:windows|mac}/{filename}")  

\d表示匹配1位数字,\d+表示匹配多位
windows|mac 表示只匹配windows或者mac
可以将上述写成
  1. map.connect("/blog/{id}", requirements={"id": R"\d+"}  
  2. map.connect("/download/{platform}/{filename}",  
  3.     requirements={"platform": R"windows|mac"})  

Format extensions

通过{.format}来指定匹配格式

  1. map.connect('/entries/{id}{.format}')  
  2. print map.match('/entries/2')  
  3. {'id': u'2''format'None}  
  4. print map.match('/entries/2.mp3')  
  5. {'id': u'2''format': u'mp3'}  

  1. map.connect('/entries/{id:\d+}{.format:mp3}')  
  2. print map.match('/entries/2.mp3')  
  3. {'id': u'2''format': u'mp3'}  
  4. print map.match('/entries/2')  
  5. {'id': u'2''format'None}  
  6. print map.match('/entries/2.mp4')  
  7. None  

注意:{id:\d+}, 如果没有\d+, print map.match('/entries/2.mp4')将输出 {'id': u'2.mp4', 'format': None}是可以成功的。
有了\d+后,由于没有匹配format,同时\d+要求只匹配数字,所有2.mp4匹配失败

当路由条目过多时,需要一条一条注册,过于麻烦,此时可以通过resource route简化

  1. map.connect("messages""/messages",  
  2.     controller="messages", action="create",  
  3.     conditions=dict(method=["POST"]))  
  4. map.connect("messages""/messages",  
  5.     controller="messages", action="index",  
  6.     conditions=dict(method=["GET"]))  
  7. map.connect("formatted_messages""/messages.{format}",  
  8.     controller="messages", action="index",  
  9.     conditions=dict(method=["GET"]))  
  10. map.connect("new_message""/messages/new",  
  11.     controller="messages", action="new",  
  12.     conditions=dict(method=["GET"]))  
  13. map.connect("formatted_new_message""/messages/new.{format}",  
  14.     controller="messages", action="new",  
  15.     conditions=dict(method=["GET"]))  
  16. map.connect("/messages/{id}",  
  17.     controller="messages", action="update",  
  18.     conditions=dict(method=["PUT"]))  
  19. map.connect("/messages/{id}",  
  20.     controller="messages", action="delete",  
  21.     conditions=dict(method=["DELETE"]))  
  22. map.connect("edit_message""/messages/{id}/edit",  
  23.     controller="messages", action="edit",  
  24.     conditions=dict(method=["GET"]))  
  25. map.connect("formatted_edit_message""/messages/{id}.{format}/edit",  
  26.     controller="messages", action="edit",  
  27.     conditions=dict(method=["GET"]))  
  28. map.connect("message""/messages/{id}",  
  29.     controller="messages", action="show",  
  30.     conditions=dict(method=["GET"]))  
  31. map.connect("formatted_message""/messages/{id}.{format}",  
  32.     controller="messages", action="show",  
  33.     conditions=dict(method=["GET"]))  

上述路由条目可以使用这一条语句代替。

  1. map.resource("message""messages")   
两个参数,一个指定单数,为member路由名字;一个指定复数,为collection路由名字。

函数原型:resource(member_name, collection_name, **kwargs)


  1. GET    /messages        => messages.index()    => url("messages")  
  2. POST   /messages        => messages.create()   => url("messages")  
  3. GET    /messages/new    => messages.new()      => url("new_message")  
  4. PUT    /messages/1      => messages.update(id) => url("message", id=1)  
  5. DELETE /messages/1      => messages.delete(id) => url("message", id=1)  
  6. GET    /messages/1      => messages.show(id)   => url("message", id=1)  
  7. GET    /messages/1/edit => messages.edit(id)   => url("edit_message", id=1)  


这里有必要说一下member 路由与 collection路由。

上述的路由模型

  1. GET    /messages        => messages.index()     
  2. POST   /messages        => messages.create()    
  3. GET    /messages/new    => messages.new()       
  4. PUT    /messages/1      => messages.update(id)  
  5. DELETE /messages/1      => messages.delete(id)  
  6. GET    /messages/1      => messages.show(id)    
  7. GET    /messages/1/edit => messages.edit(id)   

1. 有的路由有id, 指向一个具体的对象
2. 有的路由没有id, 指向全体对象
3. 有的路由(index/create, show/update/delete)有相同的URL,但是HTTP method不同
4. 有的路由(show/edit)HTTP method和前缀相同,仅后缀不同


一个member路由指定具体实例,也就是说它们有id。而一个collection路由,
没有指定的实例,即没有给定id
综上:member路由操作一个单独的实例,而collection操作全体实例。


另一个函数collection也可以完成上述功能。

函数原型:collection(collection_name, resource_name, path_prefix=None, member_prefix='/{id}', controller=None, collection_actions=['index', 'create', 'new'],member_actions=['show', 'update', 'delete', 'edit'], member_options=None, **kwargs)


用法:

map.collection('entries', 'entry')

Routes RoutesMiddleware

RoutesMiddleware将请求应声到相应WSGI程序,它将路由匹配结果存到environ环境变量中去。

  1. from routes.middleware import RoutesMiddleware  
  2. app = RoutesMiddleware(wsgi_app, map)     # ``map`` is a routes.Mapper.  

map调用match匹配URL,并设置WSGI环境变量

  1. environ['wsgiorg.routing_args'] = ((url, match))  
  2. environ['routes.route'] = route  
  3. environ['routes.url'] = url  

route为匹配到的路由,url为一个URLGenerator对象,match为匹配所得条目。


app为一个RoutesMiddleware对象,内部重载__call__(def __call__(self, environ, start_response))仍为一个wsgi应用。

wsgi_app为一个wsgi程序,RoutesMiddleware将环境变量(environ)设置好后,调用wsgi_app进行后续处理。


下面是一个实际的输出:

  1. wsgiorg.routing_args = (<routes.util.URLGenerator object at 0x0287AFB0>,   
  2.                         {'action': u'index', 'controller': <__main__.Resourse instance at 0x02876E40>})  
  3. routes.route = <routes.route.Route object at 0x02871F10>  
  4. routes.url = <routes.util.URLGenerator object at 0x0287AFB0>  
WSGI Webob Routes 实例

1.下载库文件 

   webob库:http://download.csdn.net/detail/spch2008/5497755

   routes库:http://download.csdn.net/detail/spch2008/5497757

   repoze库:http://download.csdn.net/detail/spch2008/5499231

2. 组织代码

    

3. 代码

   

  1. ''''' 
  2. Created on 2013-6-1 
  3.  
  4. @author: spch2008 
  5. '''  
  6.   
  7. from wsgiref.simple_server import make_server  
  8.   
  9. import routes.middleware  
  10. import webob.dec  
  11. import webob.exc  
  12.   
  13. class Controller:  
  14.     @webob.dec.wsgify  
  15.     def __call__(self, req):  
  16.         return webob.Response("Hello World!")  
  17.   
  18.   
  19.    
  20. class Router(object):  
  21.     def __init__(self):  
  22.         self._mapper = routes.Mapper()  
  23.         self._mapper.connect('/spch',    
  24.                         controller=Controller(),    
  25.                         action='index',    
  26.                         conditions={'method': ['GET']})    
  27.           
  28.         self._router = routes.middleware.RoutesMiddleware(self._dispatch, self._mapper)  
  29.  
  30.     @webob.dec.wsgify  
  31.     def __call__(self, req):  
  32.           
  33.         return self._router  
  34.  
  35.     @staticmethod  
  36.     @webob.dec.wsgify  
  37.     def _dispatch(req):  
  38.         match = req.environ['wsgiorg.routing_args'][1]  
  39.                   
  40.         if not match:  
  41.             return webob.exc.HTTPNotFound()  
  42.           
  43.         app = match['controller']    
  44.         return app  
  45.           
  46.         
  47.   
  48. app = Router()  
  49. httpd = make_server('localhost'8282, app)    
  50. httpd.serve_forever()   


  22行:创建一个mapper

  23行:#注册一个路由

  28行:创建一个RoutesMiddleware对象,匹配路由,修改环境变量后,调用self._dispatch


4. 运行结果

    


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:99421次
    • 积分:2706
    • 等级:
    • 排名:第13836名
    • 原创:178篇
    • 转载:21篇
    • 译文:0篇
    • 评论:9条
    文章分类
    最新评论