RESTful API: 表征狀态遷移,也就是說client端使用http的基本操作(主要四種:get, post, put, delete 對應增删改查)使服務端的資源狀态轉化;
WSGI: web server gateway interface web服務網關接口,可以看作一個橋梁,一端連這服務端(wsgi server), 一端連接配接應用程式(wsgi app),橋體(wsgi middleware),也就是說wsgi server直接處理client端的http請求,将請求内容轉譯為應用app能夠處理的對象;
api服務是入口,主要把client端發送http請求映射到具體處理函數上,主要涉及三個子產品:
paste.deploy: 建構openstack的wsgi服務, /etc下都有對應項目的paste的檔案,nova為例: /etc/nova/api-paste.ini, paste.deploy建構wsgi服務就是基于該配置檔案
webob: 對wsgi的請求和響應進行封裝(将wsgi與應用app的資訊進行處理,使用端更友善進行處理,可以放入wsgi子產品内了解)
routes: 定義url到内部函數的映射;
route 可以從url提取相應的參數,如controller,action或者其它使用者自己定義的變量
openstack中的nova-api分析:
分析:
1)webob.dec.wsgify是webob為WSGI應用程式提供的一個裝飾器,作用是将一個函數轉換成一個WSGI應用。
2)routes.middleware.RoutesMiddleware,将接受到的url,自動調用map.match()方法,将url進行路由比對并将結果存入request請求的環境變量['wsgiorg.routing_args'],最後會調用其第一個參數給出的函數接口,即self.dispatch。
3)map.connect 及map.resource均用來建立路由比對條件
針對程式中的比對條件1
map.connect('/images',controller=a,action='search',conditions={'method':['GET']})
curl
路由比對結果 (程式中的route match result is)
curl請求得到的結果
curl -X GET http://localhost:8088/images
{'action': u'search', 'controller': <__main__.controller object at 0x10c2b10>}
"do search()"
比對條件指定了curl的動作為GET ,通路路徑為images 對應的action 為search
比對條件2
map.connect('name',"/{action}/{pid}",controller=a)
curl -X GET http://localhost:8088/show/hihi
{'action': u'show', 'controller': <__main__.controller object at 0x2203b10>, 'pid': u'hihi'}
"do show()"
curl -X POST http://localhost:8088/failfunc/test
{'action': u'failfunc', 'controller': <__main__.controller object at 0x2203b10>, 'pid': u'test'}
"has no action:failfunc"
比對條件沒有指定curl的動作,是以所有的動作(PUT,POST,GET,。。)都比對,第二個curl請求,比對的action 為failfunc,pid為test,但是程式沒有定義failfunc函數,報錯
比對條件3
map.resource("message","messages",controller=a) ,map.resource内部定義了預設的比對條件
第一個參數message為 member_name(資源名),第二個參數messages為collection_name(資源集合名),一般定義資源集合名為資源名的複數,我這裡随便取名
collection_name作為通路的路徑名,且當沒有傳入參數controller時,controller=collection_name
map.resource("message","messages",controller=a) 等同于以下比對條件:
map.connect('/messages',controller=a,action='index',conditions={'method':['GET']})
map.connect('/messages',controller=a,action='create',conditions={'method':['POST']})
map.connect('/messages/{id}',controller=a,action='show',conditions={'method':['GET']})
map.connect('/messages/{id}',controller=a,action='update',conditions={'method':['PUT']})
map.connect('/messages/{id}',controller=a,action='delete',conditions={'method':['DELETE']})
前兩條是針對整個資源集合的操作,後三條是針對資源集合中某個固定資源的操作
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIn5GcuMDO1ADMlRTNkhDNxATNwIDO3MWNlNjYyYDN1QGM2AjZfdWbp9CXt92Yu4GZjlGbh5SZslmZxl3Lc9CX6MHc0RHaiojIsJye.png)
這裡比對結果中的id為某個具體資源id,這裡亂取,後三條curl針對具體資源(id為12)的操作,前兩條是針對整個資源集合的操作
當url傳入的id包含'.',會将'.'後的字元竄比對為format,如輸入的id 為 '12.hihi' ,比對id='12', format='hihi'
比對條件4
map.resource('message', 'messages',controller=a,
collection={'search':'GET','create_many':'POST'},
member={'update_many':'POST','delete_many':'POST'})
map.resource除了預設的路由條件外,還可以額外的定義‘資源集合的方法’以及‘單個資源的方法’
collection={'search':'GET','create_many':'POST'} 定義了資源集合方法 search,其curl動作為GET,create_many,其curl動作為POST
member={'update_many':'POST','delete_many':'POST'} 定義了單個資源方法 update_many,其curl動作為POST,delete_many,其curl動作為POST
比對條件5
map.resource('message', 'messages',controller=a,path_prefix='/{projectid}',
collection={'list_many':'GET','create_many':'POST'},
member={'update_many':'POST','delete_many':'POST'})
map.resource初始化時還可以指定curl通路路徑的字首路徑,如比對條件3及4沒有指定時,預設為collection_name(資源集合名)
指定path_prefix後,路徑為path_prefix/collection_name
在路由5的條件下,添加一條
map.resource('type', 'types',controller=other_controller,
parent_resource=dict(member_name='message',
collection_name='messages'),
path_prefix = '{projectid}/%s/:%s_id' %('nex','nexs'))
curl -X POST http://localhost:8088/proj1/nex/17/types
比對nexs_id 為17,controller 為other_controller, parent_resource的作用為形成name_prefix = 'message_',具體作用不詳,有待研究
參考資料:http://routes.readthedocs.org/en/latest/restful.html
疑問:
resource中的controller對象的類定義必須要有__call__,要不然,比對後變為type(controller)為unicode,原因不明,有待研究