搭建RESTful API 之 实现WSGI服务的URL映射
javarestfull 搭建参考 http://blog.csdn.net/hejias/article/details/47424511
问题引出:对于一个稍具规模的网站来说,实现的功能不可能通过一条URL来完成。如何定义多条URL,也是RESTful API考虑的问题。
需求:
本小节将考虑这样一个虚拟机管理的WSGI服务。用户可以通过发送HTTP请求,来实现对虚拟机的管理(包括创建、查询、更新以及删除虚拟机等操作)。这个WSGI服务不会真正的在物理机上创建虚拟机,只是在服务中保存相应的虚拟机记录而已。
(nova已经实现类似的功能。当用户向 Nova 发送创建虚拟机的请求时,Nova 首先会在数据库中添加相应的记录,同时在物理机上创建相应的虚拟机。
Nova必须保证数据库中保存的虚拟机信息和实际创建的虚拟机信息一致,我们直接将记录保存在内存中)
开始今天的行程:
一、基础知识
(1)、RESTful API提供一套URL的规则。在RESTful API中,每条URL都是与资源相对应的。 一个资源可能是集合,也可能是一个个体。集合通常用集合名来标志。
例如:本小节实例中,使用instances表示虚拟机的集合,而个体通常使用统一的ID标志,使用UUID标志虚拟机
(2)、对于集合的操作通常是添加和查询; 对于个体的操作是虚拟机的查询、删除和更新。对应的URL如下图示:
{instance_id}是虚拟机的UUID。将资源的ID放在URL中,是RESTful API的一大特点。
(3)、在WSGI中,要实现URL映射,主要是依赖Mapper和Controller两个类。
Mapper类用于实现URL的映射。当用户发送请求时,Mapper类会根据用户请求的URL及其方法来确定处理放入方法。
Controller类,则是实现处理HTTP请求的各种方法。
二、代码实现
1、配置文件:configure.ini
- [pipeline:main]
- pipeline = auth instance
- [app:instance]
- paste.app_factory = routers:app_factory
- [filter:auth]
- paste.filter_factory = auth:filter_factory
WSGI服务共使用了auth过滤器和instance应用程序两个部件。auth与上一节的相同,不同的是新定义了instance应用程序。instance应用程序对应的工
厂方法是routers包的app_factory方法。
2、URL映射的实现
WSGI服务使用了auth过滤器和instance应用程序两个部件。其中auth过滤器是用于HTTP头认证的,比较简单。核心功能都在instance应用程序中实现。
- from webob.dec import *
- from webob import Request,Response
- import webob.exc
- from routes import Mapper,middleware
- import controllers
- class Router(object):
- def __init__(self):
- self.mapper = Mapper()
- self.add_routes()
- self.router = middleware.RoutesMiddleware(self._dispatch, self.mapper)
- @wsgify
- def __call__(self, req):
- return self.router
- def add_routes(self):
- controller = controllers.Controller()
- self.mapper.connect('/instances', controller = controller,action = 'create', conditions = {'method' : ['POST']})
- self.mapper.connect('/instances', controller = controller,action = 'index', conditions = {'method' : ['GET']})
- self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'show', conditions = {'method' : ['GET']})
- self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'update', conditions = {'method' : ['PUT']})
- self.mapper.connect('/instances/{instance_id}', controller = controller,action = 'delete', conditions = {'method':['DELETE']})
- @staticmethod
- @wsgify
- def _dispatch(req):
- match = req.environ['wsgiorg.routing_args'][1] #获取URL解析结果
- if not match: #如果解析结果为空,则输出错误信息
- return webob.exc.HTTPNotFound()
- app = match['controller'] #获取URL对应的controller实例
- return app
- def app_factory(global_config, **local_config):
- return Router()
(1)instance应用程序对应的工厂方法为routers包的app_factory方法。app_factory方法返回一个Router对象。工厂方法必须返回一个函数的实例。
Router类中必须实现__call__方法。 Router类的__call__方法的定义。返回router变量,其实也是一个可调用的实例。
__call__是在服务器收到HTTP请求时被调用。当服务器调用__call__方法时,会转而调用router方法。
(2)Router类的初始化方法(两件事情)
- 初始化mapper成员变量。mapper成员变量是routes包的Mapper标准类,主要功能是 创建Mapper对象,用于URL解析。 然后,调用自身的add_routes方法往Mapper对象中注册URL映射
- 初始化router成员变量。 (路由匹配,修改环境变量,实现分发) router成员变量的功能将HTTP请求分发给相应的方法进行处理。router成员变量是一个 RoutesMiddleware对象。初始化需要提供两个参数-----dispatch方法和mapper变量。dispatch方法是Router类的静态方法,功能是实现HTTP请求的分发。
RoutesMiddleware对象(可调用的实例)执行过程:首先通过Mapper对象解析信息(匹配路由,修改环境变量),讲解析结果传递给dispatch方法。
(3)addroutes方法
addroutes方法共添加了5条URL路由,各条URL映射对应的功能参见上表。在添加URL映射时,调用mapper变量的connect方法。
Mapper类的connect方法用法:
<URL>:请求的URL
<controller>:处理HTTP请求的controller对象,这个对象必须是可调用的(实现了__call__方法)
<action>:指的是处理HTTP请求的方法名。所有定义的<action>对应的方法都在controller类中
<method-list>:是HTTP请求的方法列表。在RESTful API中,定义了GET、POST、PUT、DEAD和DELETE等方法,不同的方法对应资源的某项操作
action是一个字符串,指定的是方法名,而不是方法的实例。
(4)dispatch方法
首先获取URL的解析结果(通过mapper类对象进行匹配路由,修改环境变量)。如果结果为空,说明相应的URL没有在mapper对象中注册,输出错误信
息。如果不为空,返回URL对应的controller对象。由于controller对象是可调用的,最终WSGI服务会调用controller对象的__call__方法处理HTTP请
求。 (dispatch方法只是将URL请求进行分发给相应的controller,并没有具体到方法)
3、controller类的实现
- import uuid
- from webob import Request,Response
- import simplejson
- from webob.dec import wsgify
- class Controller(object):
- def __init__(self):
- self.instances = {}
- for i in range(3):
- inst_id = str(uuid.uuid4())
- self.instances[inst_id] = {'id' : inst_id, 'name' : 'inst-' + str(i)}
- print self.instances
- @wsgify
- def create(self, req):
- print req.params
- name = req.params['name']
- if name:
- inst_id = str(uuid.uuid4())
- inst = {'id' : inst_id, 'name' : name}
- self.instances[inst_id] = inst
- return {'instance' : inst}
- @wsgify
- def show(self, req, instance_id):
- inst = self.instances.get(instance_id)
- return {'instance' : inst}
- @wsgify
- def index(self, req):
- return {'instances': self.instances.values()}
- @wsgify
- def delete(self, req, instance_id):
- if self.instances.get(instance_id):
- self.instances.pop(instance_id)
- @wsgify
- def update(self, req, instance_id):
- inst = self.instances.get(instance_id)
- name = req.params['name']
- if inst and name:
- inst['name'] = name
- return {'instance': inst}
- @wsgify
- def __call__(self, req):
- arg_dict = req.environ['wsgiorg.routing_args'][1] #获取URL解析结果
- action = arg_dict.pop('action') #获取处理的方法
- del arg_dict['controller'] #删除 controller项,剩下的都是参数列表
- method = getattr(self, action) #搜索controller类中定义的方法
- result = method(req, **arg_dict) #调用方法,处理HTTP请求
- if result is None: #无返回值
- return Response(body='',status='204 Not Found',headerlist=[('Content-Type','application/json')])
- else: #有返回值
- if not isinstance(result, str):
- result = simplejson.dumps(result) #将返回值转化为字符串
- return result
(1)准备参数 (2)查找并执行controller中相应的方法 (3)返回结果
定义的 /instances/{instance_id}这样的URL。当Router的mapper对象解析这样的URL时,会把{instance_id}解析成一个参数。
例如:对于/instances/123 这条url,解析完毕后,会在以上代码的arg_dict字典中产生 {'instance_id':123}。
create方法:
功能是创建一条虚拟机记录,其对应的URL是 POST/instances。在发送请求时,必须提供name字段来指定虚拟机名。
- def create(self, req):
- print req.params
- name = req.params['name'] #获取虚拟机名
- if name:
- inst_id = str(uuid.uuid4()) #自动生成UUID
- inst = {'id' : inst_id, 'name' : name} #构造虚拟机信息元祖
- self.instances[inst_id] = inst #添加虚拟机记录
- return {'instance' : inst}
可使用req.param来获取客户端提交的数据。
代码测试:
执行python WSGIService.py,便可启动WSGI服务。WSGI服务启动后,可在另一个终端进行测试。对所有的URL进行测试:
(1)、GET /instances
WSGI服务启动时,会自动生成3条虚拟机记录。输出的结果,便是生成的3条虚拟机记录信息。
(2)、POST /instances
以上命令创建名为new-inst的虚拟机记录。
(3)、GET /instances/{instance_id}
- curl -H 'X-Auth-Token:open-sesame' -X GET > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef
{instance_id}是要查询的虚拟机的id,需要根据自己的实际情况修改。可以通过GET /instances来查看所有虚拟机记录的id
(4)、PUT /instances/{instance_id}
- curl -H 'X-Auth-Token:open-sesame' -X PUT --data 'name=new-inst2' > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef
更名虚拟机
(5)、DELETE /instances/{instance_id}
- curl -H 'X-Auth-Token:open-sesame' -X DELETE > 127.0.0.1:8000/instances/c81e83fe-ae90-44a3-89e7-20918dfa9aef
删除虚拟机
RESTful API
1、使用PasteDeploy配置WSGI服务
(1)、RESTful API底层是HTTP协议。传统HTTP协议基础上,明确定义各种HTTP方法的意义。 RESTful API定义的标准方法。
(2)、RESTful API使用PasteDeploy定制WSGI服务。WSGI服务的功能可以通过配置文件配置。在配置文件中可以定义app、filter、pipeline和composite等部件,
(3)、app和filter都须对应一个工厂方法。工厂方法通常有如下参数:
def factory(global_config, **local_config)
global_config参数保存从客户端传入的参数,例如HTTP消息体、客户上下文信息等。
local_config参数保存了在配置文件中设置的参数。
每个工厂方法最终会返回一个处理对应的app和filter HTTP请求的方法实例。处理app请求的方法实例通常有如下参数: def app(request): request参数保存HTTP请求的上下文信息。
处理filter请求的方法实例通常有如下参数:def filter(request, app):其中request参数保存HTTP请求的上下文,app参数指定从当前过滤器的下一个过滤器(或应用程序)开始,到最后一个应用程序位置所形成的的子pipeline的实例。
2、Mapper.connect方法的调用
一个完整的WSGI服务,通常需要解析和处理多条URL。routes标准包中,定义了Mapper类来实现URL映射的管理。可以通过调用Mapper对象的connect方法来向WSGI服务注册URL映射。Mapper对象的connect方法一个调用示例。
mapper.connect(url,controller=controller, action=action, conditions = condition)
(1)、url参数指定的是请求的URL。两种形式,/<resources>类型的URL对应的是集合的操作,/<resources>/<resource-id>类型的URL对应的是成员操作。<resources>是资源的集合名,<resource-id>是资源的UUID。
(2)、controller指定的是处理HTTP请求的controller对象
(3)、action参数指定controller对象中处理HTTP请求的方法
(4)、condition参数指定服务器接收和处理HTTP请求的条件。通常在condition中指定HTTP请求的方法。例如:conditions = dict(method=[‘POST’]),指定只接受HTTP POST请求,conditions =dict(method=[‘POST’,‘PUT’])指定只接收HTTP POST和PUT请求。
转http://blog.csdn.net/li_101357/article/details/52801596
搭建RESTful API 之 实现WSGI服务的URL映射的更多相关文章
- 使用CodeIgniter框架搭建RESTful API服务
使用CodeIgniter框架搭建RESTful API服务 发表于 2014-07-12 | 分类于 翻译笔记 | 6条评论 在2011年8月的时候,我写了一篇博客<使用Cod ...
- 使用 Beego 搭建 Restful API 项目
1 环境准备 首先你需要在你的环境安装以下软件: go:编程语言运行环境 git:版本控制工具 beego:go 语言流行的开发框架 bee:beego 配套的快速搭建工具 你喜欢的数据库:这里以 M ...
- Go实战--通过gin-gonic框架搭建restful api服务(github.com/gin-gonic/gin)
生命不止,继续 go go go !!! 先插播一条广告,给你坚持学习golang的理由: <2017 软件开发薪酬调查:Go 和 Scala 是最赚钱的语言> 言归正传! 之前写过使用g ...
- 玩转 SpringBoot 2 快速搭建 | RESTful Api 篇
概述 RESTful 是一种架构风格,任何符合 RESTful 风格的架构,我们都可以称之为 RESTful 架构.我们常说的 RESTful Api 是符合 RESTful 原则和约束的 HTTP ...
- 基于gin web框架搭建RESTful API服务
这篇主要学习go项目中的项目结构.项目规范等知识,ROM采用的database/sql的写法. 1.技术框架 利用的是ginweb框架,然后ROM层选用database/sql,安装mysql驱动.安 ...
- TP5.0搭建restful API 应用
1.配置环境变量,如果没配置会显示如下错误. 配置方法 1)右键此电脑-> 属性-> 高级系统设置->环境变量->Path 2)在Path后加上php目录的名称 如:E:\PH ...
- nodejs 搭建 RESTful API 服务器的常用包及其简介
常用包 框架: yarn add express 数据库链接: yarn add sequelize yarn add mysql2 处理 favicon: yarn add serve-favico ...
- 搭建RESTful API来使用Fabric Node SDK 开篇
在Balance-Transfer中,有关于Node SDK比较完备的例子. SDK的官方文档在这里:https://fabric-sdk-node.github.io/ Balance-Transf ...
- Yii2+Swagger搭建RESTful风格的API项目
在现有的Advanced Template上搭建RESTful API项目的步骤: 本案例前提说明: 本例中不使用\yii\rest\ActiveController自动创建的API,而是自定义一个A ...
随机推荐
- 【C#】 Method invocation is skipped
相信大家看到这个标题也是一头雾水了. 这个问题主要是我在项目中遇到了一个问题, 然后我通过搜索引擎搜索的关键词进而找到了answer, 我先描述一下我遇到的问题: 做项目的时候我发现log时常没有输出 ...
- kubernetes 实战5_命令_Assign Pods to Nodes&Configure a Pod to Use a ConfigMap
Assign Pods to Nodes how to assign a Kubernetes Pod to a particular node in a Kubernetes cluster. Ad ...
- Long类型转json时前端js丢失精度解决方案
一.问题背景 Java后端开发过程中,尤其是id字段,因数值太大,通过json形式传输到前端后,在js解析时,会丢失精度. 如果对精度丢失没有什么概念,可以看一个知乎的帖子,来感受一下:https:/ ...
- HDU 4557 Tree(可持久化字典树 + LCA)
http://acm.hdu.edu.cn/showproblem.php?pid=4757 题意: 给出一棵树,每个结点有一个权值,现在有多个询问,每次询问包含x,y,z三个数,求出在x到y的路径上 ...
- cmake用法及常用命令总结
CMakeLists.txt 的语法比较简单,由命令.注释和空格组成,其中命令是不区分大小写的.指令是大小写无关的,参数和变量是大小写相关的.但推荐全部使用大写指令.符号 # 后面的内容被认为是注释. ...
- Node内核基本自带模块fs 文件的读写
在node的内核中存在一些内置的模块 这些是最基本的服务端所必要的 1:node全局环境:global类似于浏览器端的window 2:文件读取模块:fs fs模块同时提供了异步和同步的方法. 'us ...
- 树莓派 无屏幕 安装Ubuntu系统 无头安装 无显示器 用网线
能看到此篇博客的人说明都尝试失败了,会发现内存卡刷入Ubuntu后,无法通过ssh操作树莓派.是因为官方的ubuntu系统在初次运行时需要设定一些东西,类似windows第一次启动也需要设置那样,如果 ...
- Docker个人理解总结
最新在学习Docker,记录下自己对Docker的理解. 一.Docker是什么? 1. Docker是一个能够把开发的应用程序自动部署到容器的开源引擎. 2.Docker使用Google公司推出的G ...
- js,jq获取父,兄弟,子节点整理
js获取节点 父: parentNode 获取已知节点的父节点. 子: childNodes; 得到全部子节点 children 得到全部子节点 firstChild 获得第一个子节点 lastChi ...
- 数据库锁机制(以MySQL为例)
选自:https://blog.csdn.net/aluomaidi/article/details/52460844 https://www.zhihu.com/question/51513268/ ...