使用了Python的Tornado框架,想发布为REST规范的webservice.综合了网上的方法,基本上有三种:
1. 直接用tornado实现:
tornado.web.RequestHandler.write() 可以输出json.
但是对于header的操作需要自己封装。
本着拿来主义的精神,还是想找现成的插件。
2. 有一个叫pyrestful的插件,可以试用一下。
步骤如下:
a. pip install pyrestful
b. 可以参考官方文档,我的代码片段如下:
*入口代码:
#!/usr/bin/python
#-*- coding: utf-8 -*-
__author__ = 'stone'
import tornado.ioloop
import pyrestful.rest
import os
os.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'
import logging
from common.Log import LogInit
from common.Cfg import config
from business.Customer import CustomerResource
LogInit("loggingREST.conf")
cfg = config(filename="config4REST.conf")
#a list to route different REST Service.
restservices = []
restservices.append(CustomerResource)
if __name__ == "__main__":
loggerRoot = logging.getLogger('root')
loggerRoot.debug("start run REST module.")
try:
app = pyrestful.rest.RestService(restservices)
port = cfg.get('port','port')
app.listen(port)
tornado.ioloop.IOLoop.instance().start()
except Exception,ex:
pass
*服务代码:
__author__ = 'stone'#-*- coding: utf-8 -*-import osos.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'import pyrestful.restfrom pyrestful import mediatypesfrom pyrestful.rest import get, post, put, deleteimport loggingimport torndb
class Customer(object):def __init__(self,id_customer=0, name_customer=None, address_customer=None):self.id_customer = id_customerself.name_customer = name_customerself.address_customer = address_customer
# Settersdef setId_Customer(self,id_customer):self.id_customer = id_customerdef setName_Customer(self,name_customer):self.name_customer = name_customerdef setAddress_Customer(self,address_customer):self.address_customer = address_customer
# Gettersdef getId_Customer(self):return self.id_customerdef getName_Customer(self):return self.name_customerdef getAddress_Customer(self):return self.address_customer
class CustomerDataBase(object):customerDB = dict()id_seq = 1def insert(self, name_customer, address_customer):sequence = self.id_seqcustomer = Customer(sequence, name_customer, address_customer)self.customerDB[sequence] = customerself.id_seq += 1return sequence
def update(self,id_customer, name_customer, address_customer):if self.exists(id_customer):customer = self.customerDB[id_customer]customer.setName_Customer(name_customer)customer.setAddress_Customer(address_customer)self.customerDB[id_customer] = customerreturn Trueelse:return False
def delete(self,id_customer):if self.exists(id_customer):del self.customerDB[id_customer]return Trueelse:return False
def find(self,id_customer):if self.exists(id_customer):return self.customerDB[id_customer]else:return None
def exists(self,id_customer):if id_customer in self.customerDB:return Trueelse:return False
class CustomerResource(pyrestful.rest.RestHandler):"""a class for Customer Resource."""def initialize(self):"""special initial for tornado.web.RequestHandler."""loggerRoot = logging.getLogger('root')loggerRoot.debug("start CustomerResource module.")self.database = CustomerDataBase()
#REST-GET@get(_path="/customer/{id_customer}",_types=[int],_produces=mediatypes.APPLICATION_JSON)def getTest(self,id_customer):try:if not self.database.exists(id_customer):self.gen_http_error(404,"Error 404 : do not exists the customer : %d"%id_customer)return
customer = self.database.find(id_customer)
response = dict()response['id_customer'] = customer.getId_Customer()response['name_customer'] = customer.getName_Customer()response['address_customer'] = customer.getAddress_Customer()return responseexcept Exception,ex:pass
#REST-POST@post(_path="/customer", _types=[str,str], _produces=mediatypes.APPLICATION_JSON)def createCustomer(self, name_customer, address_customer):try:id_customer = self.database.insert(name_customer, address_customer)return {"created_customer_id": id_customer}except Exception,ex:pass
#REST-PUT@put(_path="/customer/{id_customer}", _types=[int,str,str], _produces=mediatypes.APPLICATION_JSON)def updateCustomer(self, id_customer, name_customer, address_customer):try:if not self.database.exists(id_customer):self.gen_http_error(404,"Error 404 : do not exists the customer : %d"%id_customer)returnupdated = self.database.update(id_customer,name_customer,address_customer)return {"updated_customer_id": id_customer, "success":updated}except Exception,ex:pass
#REST-DELETE@delete(_path="/customer/{id_customer}", _types=[int], _produces=mediatypes.APPLICATION_JSON)def deleteCustomer(self,id_customer):try:if not self.database.exists(id_customer):self.gen_http_error(404,"Error 404 : do not exists the customer : %d"%id_customer)returndeleted = self.database.delete(id_customer)return {"delete_customer_id": id_customer, "success":deleted}except Exception,ex:pass
经过测试可用。
3. 但是,之前用的web.py框架时,有一个叫做mimerender的插件,封装比这个优雅,想用起来,这一折腾就花了3天,最终调通,使用方法如下:
a. pip install mimerender.
b. hacker mimerender的代码,添加tornado的支持,片段如下:
# tornado implementationtry:import tornado.webclass TornadoMimeRender(MimeRenderBase):"""a class for tornado mimerender.2014.11.13. stone spend a week to use it.we need set the handler from front app."""
#a class hander for tornadolocalHandler = tornado.web.RequestHandlerdef setHandler(self,reqHandler):"""set the handler for tornado."""self.localHandler = reqHandler
def _get_request_parameter(self, key, default=None):#tornado.web.RequestHandler.get_argument()return self.localHandler.get_argument(key,default)
def _get_accept_header(self, default=None):return self.localHandler.request.headers['ACCEPT']
def _set_context_var(self, key, value):#tornado.web.RequestHandler.__setattr__(key,value)self.localHandler.__setattr__(key,value)
def _clear_context_var(self, key):#tornado.web.RequestHandler.__delattr__(key)self.localHandler.__delattr__(key)
def _make_response(self, content, content_type, status):#tornado.web.RequestHandler.set_status(status)# we only need first 3 int.self.localHandler.set_status(int(status[0:3]))#tornado.web.RequestHandler.set_header('Content-Type',content_type)self.localHandler.set_header('Content-Type',content_type)self.localHandler.write(content)
except ImportError:pass
c. 使用的代码片段如下:
#!/usr/bin/python#-*- coding: utf-8 -*-__author__ = 'stone'import tornado.ioloopimport tornado.webimport mimerenderimport jsonimport osos.environ['NLS_LANG'] = 'SIMPLIFIED CHINESE_CHINA.UTF8'import loggingfrom common.Log import LogInitfrom common.Cfg import config
LogInit("loggingREST.conf")
cfg = config(filename="config4REST.conf")
mimerender = mimerender.TornadoMimeRender()
render_xml = lambda message: '<message>this is xml:%s</message>'%messagerender_json = lambda **args: json.dumps(args)render_html = lambda message: '<html><body>this is html:%s</body></html>'%messagerender_txt = lambda message: message
class Mimeservice(tornado.web.RequestHandler):"""a mime render test service."""
#use mimerender#step 1: set the handler.def initialize(self):"""special init for tornado.web.RequestHandler class.set the handler for mime render."""mimerender.setHandler(self)
#use mimerender#step 2: define mimerender format.@mimerender(default = 'json',html = render_html,xml = render_xml,json = render_json,txt = render_txt)#use mimerender#step 3: same with the all mimerender.def get(self):return {'message':'Hello'}
application = tornado.web.Application([(r"/mimeservice",Mimeservice),(r"/mime",Mimeservice)])
if __name__ == "__main__":loggerRoot = logging.getLogger('root')loggerRoot.debug("start run REST module in mimerender.")try:port = cfg.get('port','port')application.listen(port)tornado.ioloop.IOLoop.instance().start()except Exception,ex:pass
经测,可用,折腾死我了。