11.2.4、搭建RESTful API 之 利用类来实现

来源:互联网 发布:网络覆盖 新方法 编辑:程序博客网 时间:2024/06/06 00:08

通过上一节的学习,已经可以很容易的添加和删除功能模块了。但是还存在一下不足:

(1)、上一节过滤器和应用程序都是用方法来实现的。对于实现比较复杂的功能显然不是很好

(2)、通过httpd.serve_forever()来启动WSGI服务,使得一个进程对应一个WSGI服务。对于ESGI服务的启动、关闭和暂停都需要直接

对进程进行操作,带来了很多不便。

(3)、利用类来实现过滤器和一个应用程序

(4)、利用eventlet库(用于线程管理的标准python库)来启动WSGI服务  http://eventlet.net/doc/modules/wsgi.html  

代码分析:

实例中定义的类说明:

类名       所属文件      描述

Auth       auth.py       实现auth过滤器的类

Hello      hello.py      实现hello应用程序的类

Loader     loader.py      用于加载服务的应用程序 

Server     server.py      实现一个WSGI服务,主要实现对线程的创建、配置和管理

WSGIService  WSGIService.py  用于对WSGI服务的管理,包括服务的启动、停止和监听等


配置文件:

#configure.ini[pipeline:main]pipeline = auth hello[app:hello]paste.app_factory = hello:app_factory[filter:auth]paste.filter_factory = auth:filter_factory

Auth类:

from webob.dec import *from webob import Request,Responsefrom webob import excclass Auth(object):    def __init__(self, app):        self.app = app    @wsgify    def __call__(self, req):        print 'Auth class'        resp = self.process_request(req)        if resp:            return resp        return self.app(req)    @wsgify    def process_request(self, req):        if req.headers.get('X-Auth-Token') != 'open-sesame':            return exc.HTTPForbidden()@wsgify.middlewaredef filter_factory(app, global_config, **local_config):    return Auth(app)

filter_factory工厂方法,返回的是Auth类的实例对象。这个方法在configure.ini文件中引用。

__call__函数实现auth过滤器功能逻辑的方法。 工厂方法返回的应该是一个 callable 的对象。要使用类实现过滤器或者应用程序

时,必须在类中定义__call__方法。当过滤器或应用程序接收到HTTP请求时,会调用类中的__call__方法。


Hello类:

from webob.dec import *from webob import Request,Responseclass Hello(object):    @wsgify    def __call__(self,req):        return Response('hello world!\n')def app_factory(global_config, **local_config):    return Hello()

实现一个__call__方法。 在auth过滤器中定义类方法来作为工厂方法,而在hello应用程序中采用的是外部方法作为工厂方法。

(根据个人习惯实现工厂函数,我比较倾向于类外定义工厂方法,逻辑比较清晰)

Loader类:

from paste.deploy import loadappimport osclass Loader(object):    def __init__(self, configname, appname):        self.configname = configname        self.appname = appname    def loadapp_file(self):        wsgi_app = loadapp('config:%s' % (os.path.abspath(self.configname)), self.appname)        return wsgi_app

该类是通过调用paste.deploy中的loadapp来加载应用程序。


Server类:这个类的主要功能是实现对线程的创建和管理。

import eventlet   #前面介绍过这个库,主要是网络和线程池import eventlet.wsgiimport greenletclass Server(object):    def __init__(self, app, hostname = '127.0.0.1', port = 0):        self._pool = eventlet.GreenPool(10)  #创建线程池,允许并行访问        self.app = app    #WSGI服务的应用程序        self._socket = eventlet.listen((hostname, port), backlog = 10) #创建监听的socket        (self.hostname, self.port) = self._socket.getsockname()        print 'listening on %s : %d' % (self.hostname, self.port)    def start(self):  <pre name="code" class="python">                       #http://eventlet.net/doc/modules/wsgi.html eventlet.wsgi.server
self._server = eventlet.spawn(eventlet.wsgi.server, self._socket, self.app, protocol = eventlet.wsgi.HttpProtocol, custom_pool=self._pool) def stop(self): if self._server is not None: self._pool.resize(0) def wait(self): try: self._server.wait() except greenlet.GreenletExit: print 'WSGI server has stopped.'

eventlet.wsgi.server函数:

eventlet.wsgi.server(sock, site, log=None, environ=None, max_size=None, max_http_version='HTTP/1.1',protocol=<class 'eventlet.wsgi.HttpProtocol'>, server_event=None, minimum_chunk_size=None,log_x_forwarded_for=True,custom_pool=None, keepalive=True, log_output=True, log_format='%(client_ip)s - - [%(date_time)s] "%(request_line)s" %(status_code)s %(body_length)s %(wall_seconds).6f',url_length_limit=8192, debug=True, socket_timeout=None, capitalize_response_headers=True)

启动一个从提供的服务器套接字处理请求WSGI服务器。函数一直循环执行。在服务器退出后sock对象将被关闭, 但潜在的文件描述

符仍然打开着,所以如果你有一个sock的副本,它将仍然可用。  

Warning:

 At the moment server() will always wait for active connections to finish before exiting, even if there’s an exception raised inside it (all exceptions are handled the same way, includinggreenlet.GreenletExit and those inheriting from BaseException).
While this may not be an issue normally, when it comes to long running HTTP connections (like eventlet.websocket) it will become problematic and calling wait() on a thread that runs the server may hang, even after using kill(), as long as there are active connections.

参数说明:

sock – Server socket, must be already bound to a port and listening.

site – WSGI application function.

protocol – Protocol class. Deprecated.

custom_pool – A custom GreenPool instance which is used to spawn client green threads. If this is supplied, max_size is ignored.

WSGIService类:

import loaderimport serverclass WSGIService(object):    def __init__(self, configname, appname):        self.loader = loader.Loader(configname, appname)        self.app = self.loader.loadapp_file()        self.server = server.Server(self.app, '127.0.0.1', 8000)    def start(self):        self.server.start()    def wait(self):        self.server.wait()    def stop(self):        self.server.stop()if __name__ == "__main__":    configname = 'configure.ini'    appname = 'main'    server = WSGIService(configname, appname)    server.start()    server.wait()
调用server类的start、stop和wait方法。


代码测试:











0 0
原创粉丝点击